diff --git a/.codecov.yml b/.codecov.yml index c3e739b1..a5557e7b 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -18,7 +18,7 @@ comment: behavior: default flags: null paths: null - + ignore: - "pygromos/data/" # ignore folders and all its contents - "pygromos/tests/" # ignore test files diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 778aad19..2693fd8f 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,7 +1,7 @@ # How to contribute We welcome contributions from external contributors, and this document -describes how to merge code changes into this pygromos. +describes how to merge code changes into this pygromos. ## Getting Started diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index c772b96d..26da5a2f 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -9,4 +9,4 @@ Notable points that this PR has either accomplished or will accomplish. - [ ] Question1 ## Status -- [ ] Ready to go \ No newline at end of file +- [ ] Ready to go diff --git a/.github/workflows/CI.yaml b/.github/workflows/CI.yaml index 0e57ac50..a5d2f5e6 100644 --- a/.github/workflows/CI.yaml +++ b/.github/workflows/CI.yaml @@ -42,8 +42,8 @@ jobs: python-version: ${{ matrix.python-version }} environment-file: dev/conda_envs/test_env.yaml channels: conda-forge,defaults - - activate-environment: test + + activate-environment: pygromosTest auto-update-conda: true auto-activate-base: false show-channel-urls: true @@ -63,12 +63,11 @@ jobs: shell: bash -l {0} run: | - pytest -v --color=yes pygromos/tests/ --cov=pygromos --cov-report=xml - + pytest -v --color=yes pygromos/tests/ --cov=pygromos --cov-report=xml + - name: CodeCov uses: codecov/codecov-action@v1 with: file: ./coverage.xml flags: unittests name: codecov-${{ matrix.os }}-py${{ matrix.python-version }} - diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml new file mode 100644 index 00000000..95045737 --- /dev/null +++ b/.github/workflows/pre-commit.yml @@ -0,0 +1,14 @@ +name: pre-commit + +on: + pull_request: + push: + branches: [main, release3, PyGromosTools_V1] + +jobs: + pre-commit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + - uses: pre-commit/action@v2.0.3 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..647eb8bf --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,66 @@ +repos: + + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.1.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + args: ["--unsafe"] + - id: check-added-large-files + + - repo: https://github.com/psf/black + rev: 22.1.0 + hooks: + - id: black + name: Fixes formatting + language_version: python3 + args: ["--line-length=120"] + + + # - repo: https://gitlab.com/pycqa/flake8 + # rev: 3.8.4 + # hooks: + # - id: flake8 + # name: Checks pep8 style + # args: [ + # "--max-line-length=120", + # # Ignore imports in init files + # "--per-file-ignores=*/__init__.py:F401,setup.py:E121", + # # ignore long comments (E501), as long lines are formatted by black + # # ignore Whitespace before ':' (E203) + # # ignore Line break occurred before a binary operator (W503) + # "--ignore=E501,E203,W503", + # # needed to not remove * imports (for example in _all_blocks.py) + # "--ignore=F405", + # ] + + # - repo: local + # hooks: + + # - id: jupyisort + # name: Sorts ipynb imports + # entry: jupytext --pipe-fmt ".py" --pipe "isort - --multi-line=3 --trailing-comma --force-grid-wrap=0 --use-parentheses --line-width=99" --sync + # files: \.ipynb$ + # language: python + + # - id: jupyblack + # name: Fixes ipynb format + # entry: jupytext --pipe-fmt ".py" --pipe "black - --line-length=120" --sync + # files: \.ipynb$ + # language: python + + # - id: nbconvert + # name: Removes ipynb content + # entry: jupyter nbconvert + # args: + # [ + # "--ClearOutputPreprocessor.enabled=True", + # "--ClearMetadataPreprocessor.enabled=True", + # "--RegexRemovePreprocessor.enabled=True", + # "--to=notebook", + # "--log-level=ERROR", + # "--inplace", + # ] + # files: \.ipynb$ + # language: python diff --git a/INSTALL.md b/INSTALL.md index 2263faab..28257f54 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -9,7 +9,7 @@ Make sure to have the following packages installed: ```bash #with pip installer: -pip install +pip install #or if you use conda: conda install ``` diff --git a/MANIFEST.in b/MANIFEST.in index d6198cfd..988a2fbe 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -3,4 +3,4 @@ include MANIFEST.in include versioneer.py graft pygromos -global-exclude *.py[cod] __pycache__ *.so \ No newline at end of file +global-exclude *.py[cod] __pycache__ *.so diff --git a/README.md b/README.md index 7d159955..34d23de7 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ -![](.img/PyGromosToolsBanner.png) +![PyGromosBan](.img/PyGromosToolsBanner.png) Welcome to PyGromosTools ============================== + [//]: # (Badges) [![CI](https://github.com/rinikerlab/PyGromosTools/actions/workflows/CI.yaml/badge.svg)](https://github.com/rinikerlab/PyGromosTools/actions/workflows/CI.yaml) [![codecov](https://codecov.io/gh/rinikerlab/PyGromosTools/branch/main/graph/badge.svg?token=R36KJCEKEC)](https://codecov.io/gh/rinikerlab/PyGromosTools) @@ -11,12 +12,12 @@ Welcome to PyGromosTools General ------------- + The aim of the module is to bring GROMOS to the Python3 World! This repository should make it easier to work with GROMOS in Python and should enable the user to write cleaner, more reliable and adaptable code. General informations about functions can be found in our wiki and usage example for many general functions and theire relations are shown in jupyter notebooks in the examples in the example folder. - Content ------------- @@ -95,26 +96,30 @@ Content * easy to automatize and combine with analysis routines Run on a local machine: + ```python from pygromos.files.gromos_system import Gromos_System from pygromos.simulations.hpc_queuing.submission_systems.local import LOCAL as subSystem from pygromos.simulations.modules.preset_simulation_modules import emin # define file paths + root_dir = "./example_files/SD_Simulation" root_in_dir = root_dir+"/SD_input" cnf_path = root_in_dir+"/6J29_unitedatom_optimised_geometry.cnf" top_path = root_in_dir + "/6J29.top" sys_name = "6J29" -# Build gromos System: +# Build gromos System + grom_system = Gromos_System(in_cnf_path=cnf_path, in_top_path=top_path, system_name=sys_name, work_folder=root_in_dir) - + # Run Emin + emin_gromos_system, jobID = emin(in_gromos_system=grom_system, project_dir=root_dir, step_name=step_name, submission_system=subSystem()) - + ``` Run on LSF-Cluster: @@ -133,12 +138,12 @@ Content # Build gromos System: grom_system = Gromos_System(in_cnf_path=cnf_path, in_top_path=top_path, system_name=sys_name, work_folder=root_in_dir) - + # Run Emin sub_system = subSystem(nmpi=4) # allows parallelization emin_gromos_system, jobID = emin(in_gromos_system=grom_system, project_dir=root_dir, step_name=step_name, submission_system=sub_system) - + ``` * Other utilities: @@ -150,21 +155,24 @@ General Information ### Specifications - * Python >=3.7: - * requires: numpy, scipy, pandas, rdkit +* Python >=3.7: +* requires: numpy, scipy, pandas, rdkit - * optional: openforcefield for OpenForceField and Serenityff functions +* optional: openforcefield for OpenForceField and Serenityff functions ### SETUP see INSTALL.md file for more informations +### Contributions + +For any contribution, please check out the CODE_OF_CONDUCT.md file and the style guide in styleguide.md. + ### Copyright Copyright (c) 2020, Benjamin Ries, Marc Lehner, Salome Rieder ### Acknowledgements - -Project based on the -[Computational Molecular Science Python Cookiecutter](https://github.com/molssi/cookiecutter-cms) version 1.3. +Project based on the +[Computational Molecular Science Python Cookiecutter](https://github.com/molssi/cookiecutter-cms) version 1.3. diff --git a/conda_env.yaml b/conda_env.yaml new file mode 100644 index 00000000..00f84d68 --- /dev/null +++ b/conda_env.yaml @@ -0,0 +1,30 @@ +name: pygromos +channels: + - conda-forge + - defaults +dependencies: + # Base depends + - python + - pip + ## Testing + - pytest + ## Meta + - typing + - pre-commit + - jupyter + - tqdm + - ipywidgets + # Science + - mpmath + - pandas + - pytables + - numpy + - sympy + - scipy + ## Chemie + - openff-toolkit = 0.10.0 + - mdtraj + - rdkit + ## Visualization + - matplotlib + - nglview diff --git a/dev/conda_envs/dev_env.yaml b/dev/conda_envs/dev_env.yaml index 38cb9203..c9cd4958 100644 --- a/dev/conda_envs/dev_env.yaml +++ b/dev/conda_envs/dev_env.yaml @@ -1,29 +1,36 @@ name: pygromosDev channels: - - rdkit - conda-forge - defaults dependencies: # Base depends - python - pip - # Testing + ## Testing - pytest - pytest-cov - codecov - #meta + ## Meta - typing + - pre-commit + - jupyter - tqdm - ipywidgets - #science - - openff-toolkit + ## Documentation + - sphinx + - m2r + - nbsphinx + # Science + - mpmath - pandas - pytables - numpy - sympy - scipy + ## Chemie + - openff-toolkit = 0.10.0 + - mdtraj - rdkit - - mpmath - ##Visualization + ## Visualization - matplotlib - - py3dmol + - nglview diff --git a/dev/conda_envs/test_env.yaml b/dev/conda_envs/test_env.yaml index ec6c6778..4dc88494 100644 --- a/dev/conda_envs/test_env.yaml +++ b/dev/conda_envs/test_env.yaml @@ -1,32 +1,30 @@ -name: test +name: pygromosTest channels: - - rdkit - conda-forge - defaults dependencies: # Base depends - python - pip - # Testing + ## Testing - pytest - pytest-cov - codecov - #meta + ## Meta - typing - - tqdm - - ipywidgets - #science - - openff-toolkit = 0.10.0 + - pre-commit + # Science + - mpmath - pandas - pytables - numpy - sympy - scipy + ## Chemie + - openff-toolkit = 0.10.0 + - mdtraj - rdkit - - mpmath - ##Visualization + ## Visualization - matplotlib - - py3dmol - - - + - py3dmol #to be removed! soon after merge of new visualize + - nglview diff --git a/docs/.nojekyll b/docs/.nojekyll index 8b137891..e69de29b 100644 --- a/docs/.nojekyll +++ b/docs/.nojekyll @@ -1 +0,0 @@ - diff --git a/docs/Examples/example_PyGromosPP.html b/docs/Examples/example_PyGromosPP.html index c4683360..7691b3b8 100644 --- a/docs/Examples/example_PyGromosPP.html +++ b/docs/Examples/example_PyGromosPP.html @@ -4,68 +4,68 @@ - + - + Demonstartion of the PyGromosTools implementation of the Gromos++ programs — PyGromosTools documentation - - + + - - - - - - + + + + + + - - + + - + - + - + - +
- +
- +
- +
- - + + @@ -147,31 +147,31 @@
    - +
  • »
  • - +
  • Examples »
  • - +
  • Demonstartion of the PyGromosTools implementation of the Gromos++ programs
  • - - + +
  • - - + + View page source - - + +
  • - +
- +
- - + + ",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML="",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document); \ No newline at end of file +!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML="",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document); diff --git a/docs/_static/js/html5shiv.min.js b/docs/_static/js/html5shiv.min.js index cd1c674f..b4011dd6 100644 --- a/docs/_static/js/html5shiv.min.js +++ b/docs/_static/js/html5shiv.min.js @@ -1,4 +1,4 @@ /** * @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed */ -!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document); \ No newline at end of file +!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document); diff --git a/docs/_static/js/theme.js b/docs/_static/js/theme.js index 839d07e2..6992be53 100644 --- a/docs/_static/js/theme.js +++ b/docs/_static/js/theme.js @@ -1 +1 @@ -!function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap("
"),n("table.docutils.footnote").wrap("
"),n("table.docutils.citation").wrap("
"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n(''),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}t.length>0&&($(".wy-menu-vertical .current").removeClass("current"),t.addClass("current"),t.closest("li.toctree-l1").addClass("current"),t.closest("li.toctree-l1").parent().addClass("current"),t.closest("li.toctree-l1").addClass("current"),t.closest("li.toctree-l2").addClass("current"),t.closest("li.toctree-l3").addClass("current"),t.closest("li.toctree-l4").addClass("current"),t.closest("li.toctree-l5").addClass("current"),t[0].scrollIntoView())}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current"),e.siblings().find("li.current").removeClass("current"),e.find("> ul li.current").removeClass("current"),e.toggleClass("current")}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t
"),n("table.docutils.footnote").wrap("
"),n("table.docutils.citation").wrap("
"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n(''),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}t.length>0&&($(".wy-menu-vertical .current").removeClass("current"),t.addClass("current"),t.closest("li.toctree-l1").addClass("current"),t.closest("li.toctree-l1").parent().addClass("current"),t.closest("li.toctree-l1").addClass("current"),t.closest("li.toctree-l2").addClass("current"),t.closest("li.toctree-l3").addClass("current"),t.closest("li.toctree-l4").addClass("current"),t.closest("li.toctree-l5").addClass("current"),t[0].scrollIntoView())}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current"),e.siblings().find("li.current").removeClass("current"),e.find("> ul li.current").removeClass("current"),e.toggleClass("current")}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t=0&&t<=m}}function $(n){return function(r){return null==r?void 0:r[n]}}var G=$("byteLength"),H=J(G),Q=/\[object ((I|Ui)nt(8|16|32)|Float(32|64)|Uint8Clamped|Big(I|Ui)nt64)Array\]/;var X=c?function(n){return h?h(n)&&!q(n):H(n)&&Q.test(a.call(n))}:K(!1),Y=$("length");function Z(n,r){r=function(n){for(var r={},t=n.length,e=0;e":">",'"':""","'":"'","`":"`"},Kn=Ln(Cn),Jn=Ln(_n(Cn)),$n=tn.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g},Gn=/(.)^/,Hn={"'":"'","\\":"\\","\r":"r","\n":"n","\u2028":"u2028","\u2029":"u2029"},Qn=/\\|'|\r|\n|\u2028|\u2029/g;function Xn(n){return"\\"+Hn[n]}var Yn=0;function Zn(n,r,t,e,u){if(!(e instanceof r))return n.apply(t,u);var o=Mn(n.prototype),i=n.apply(o,u);return _(i)?i:o}var nr=j((function(n,r){var t=nr.placeholder,e=function(){for(var u=0,o=r.length,i=Array(o),a=0;a1)er(a,r-1,t,e),u=e.length;else for(var f=0,c=a.length;f0&&(t=r.apply(this,arguments)),n<=1&&(r=null),t}}var cr=nr(fr,2);function lr(n,r,t){r=qn(r,t);for(var e,u=nn(n),o=0,i=u.length;o0?0:u-1;o>=0&&o0?a=o>=0?o:Math.max(o+f,a):f=o>=0?Math.min(o+1,f):o+f+1;else if(t&&o&&f)return e[o=t(e,u)]===u?o:-1;if(u!=u)return(o=r(i.call(e,a,f),C))>=0?o+a:-1;for(o=n>0?a:f-1;o>=0&&o0?0:i-1;for(u||(e=r[o?o[a]:a],a+=n);a>=0&&a=3;return r(n,Fn(t,u,4),e,o)}}var wr=_r(1),Ar=_r(-1);function xr(n,r,t){var e=[];return r=qn(r,t),mr(n,(function(n,t,u){r(n,t,u)&&e.push(n)})),e}function Sr(n,r,t){r=qn(r,t);for(var e=!tr(n)&&nn(n),u=(e||n).length,o=0;o=0}var Er=j((function(n,r,t){var e,u;return D(r)?u=r:(r=Nn(r),e=r.slice(0,-1),r=r[r.length-1]),jr(n,(function(n){var o=u;if(!o){if(e&&e.length&&(n=In(n,e)),null==n)return;o=n[r]}return null==o?o:o.apply(n,t)}))}));function Br(n,r){return jr(n,Rn(r))}function Nr(n,r,t){var e,u,o=-1/0,i=-1/0;if(null==r||"number"==typeof r&&"object"!=typeof n[0]&&null!=n)for(var a=0,f=(n=tr(n)?n:jn(n)).length;ao&&(o=e);else r=qn(r,t),mr(n,(function(n,t,e){((u=r(n,t,e))>i||u===-1/0&&o===-1/0)&&(o=n,i=u)}));return o}function Ir(n,r,t){if(null==r||t)return tr(n)||(n=jn(n)),n[Wn(n.length-1)];var e=tr(n)?En(n):jn(n),u=Y(e);r=Math.max(Math.min(r,u),0);for(var o=u-1,i=0;i1&&(e=Fn(e,r[1])),r=an(n)):(e=Pr,r=er(r,!1,!1),n=Object(n));for(var u=0,o=r.length;u1&&(t=r[1])):(r=jr(er(r,!1,!1),String),e=function(n,t){return!Mr(r,t)}),qr(n,e,t)}));function Wr(n,r,t){return i.call(n,0,Math.max(0,n.length-(null==r||t?1:r)))}function zr(n,r,t){return null==n||n.length<1?null==r||t?void 0:[]:null==r||t?n[0]:Wr(n,n.length-r)}function Lr(n,r,t){return i.call(n,null==r||t?1:r)}var Cr=j((function(n,r){return r=er(r,!0,!0),xr(n,(function(n){return!Mr(r,n)}))})),Kr=j((function(n,r){return Cr(n,r)}));function Jr(n,r,t,e){A(r)||(e=t,t=r,r=!1),null!=t&&(t=qn(t,e));for(var u=[],o=[],i=0,a=Y(n);ir?(e&&(clearTimeout(e),e=null),a=c,i=n.apply(u,o),e||(u=o=null)):e||!1===t.trailing||(e=setTimeout(f,l)),i};return c.cancel=function(){clearTimeout(e),a=0,e=u=o=null},c},debounce:function(n,r,t){var e,u,o=function(r,t){e=null,t&&(u=n.apply(r,t))},i=j((function(i){if(e&&clearTimeout(e),t){var a=!e;e=setTimeout(o,r),a&&(u=n.apply(this,i))}else e=or(o,r,this,i);return u}));return i.cancel=function(){clearTimeout(e),e=null},i},wrap:function(n,r){return nr(r,n)},negate:ar,compose:function(){var n=arguments,r=n.length-1;return function(){for(var t=r,e=n[r].apply(this,arguments);t--;)e=n[t].call(this,e);return e}},after:function(n,r){return function(){if(--n<1)return r.apply(this,arguments)}},before:fr,once:cr,findKey:lr,findIndex:pr,findLastIndex:vr,sortedIndex:hr,indexOf:gr,lastIndexOf:dr,find:br,detect:br,findWhere:function(n,r){return br(n,Dn(r))},each:mr,forEach:mr,map:jr,collect:jr,reduce:wr,foldl:wr,inject:wr,reduceRight:Ar,foldr:Ar,filter:xr,select:xr,reject:function(n,r,t){return xr(n,ar(qn(r)),t)},every:Sr,all:Sr,some:Or,any:Or,contains:Mr,includes:Mr,include:Mr,invoke:Er,pluck:Br,where:function(n,r){return xr(n,Dn(r))},max:Nr,min:function(n,r,t){var e,u,o=1/0,i=1/0;if(null==r||"number"==typeof r&&"object"!=typeof n[0]&&null!=n)for(var a=0,f=(n=tr(n)?n:jn(n)).length;ae||void 0===t)return 1;if(t=0&&t<=m}}function $(n){return function(r){return null==r?void 0:r[n]}}var G=$("byteLength"),H=J(G),Q=/\[object ((I|Ui)nt(8|16|32)|Float(32|64)|Uint8Clamped|Big(I|Ui)nt64)Array\]/;var X=c?function(n){return h?h(n)&&!q(n):H(n)&&Q.test(a.call(n))}:K(!1),Y=$("length");function Z(n,r){r=function(n){for(var r={},t=n.length,e=0;e":">",'"':""","'":"'","`":"`"},Kn=Ln(Cn),Jn=Ln(_n(Cn)),$n=tn.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g},Gn=/(.)^/,Hn={"'":"'","\\":"\\","\r":"r","\n":"n","\u2028":"u2028","\u2029":"u2029"},Qn=/\\|'|\r|\n|\u2028|\u2029/g;function Xn(n){return"\\"+Hn[n]}var Yn=0;function Zn(n,r,t,e,u){if(!(e instanceof r))return n.apply(t,u);var o=Mn(n.prototype),i=n.apply(o,u);return _(i)?i:o}var nr=j((function(n,r){var t=nr.placeholder,e=function(){for(var u=0,o=r.length,i=Array(o),a=0;a1)er(a,r-1,t,e),u=e.length;else for(var f=0,c=a.length;f0&&(t=r.apply(this,arguments)),n<=1&&(r=null),t}}var cr=nr(fr,2);function lr(n,r,t){r=qn(r,t);for(var e,u=nn(n),o=0,i=u.length;o0?0:u-1;o>=0&&o0?a=o>=0?o:Math.max(o+f,a):f=o>=0?Math.min(o+1,f):o+f+1;else if(t&&o&&f)return e[o=t(e,u)]===u?o:-1;if(u!=u)return(o=r(i.call(e,a,f),C))>=0?o+a:-1;for(o=n>0?a:f-1;o>=0&&o0?0:i-1;for(u||(e=r[o?o[a]:a],a+=n);a>=0&&a=3;return r(n,Fn(t,u,4),e,o)}}var wr=_r(1),Ar=_r(-1);function xr(n,r,t){var e=[];return r=qn(r,t),mr(n,(function(n,t,u){r(n,t,u)&&e.push(n)})),e}function Sr(n,r,t){r=qn(r,t);for(var e=!tr(n)&&nn(n),u=(e||n).length,o=0;o=0}var Er=j((function(n,r,t){var e,u;return D(r)?u=r:(r=Nn(r),e=r.slice(0,-1),r=r[r.length-1]),jr(n,(function(n){var o=u;if(!o){if(e&&e.length&&(n=In(n,e)),null==n)return;o=n[r]}return null==o?o:o.apply(n,t)}))}));function Br(n,r){return jr(n,Rn(r))}function Nr(n,r,t){var e,u,o=-1/0,i=-1/0;if(null==r||"number"==typeof r&&"object"!=typeof n[0]&&null!=n)for(var a=0,f=(n=tr(n)?n:jn(n)).length;ao&&(o=e);else r=qn(r,t),mr(n,(function(n,t,e){((u=r(n,t,e))>i||u===-1/0&&o===-1/0)&&(o=n,i=u)}));return o}function Ir(n,r,t){if(null==r||t)return tr(n)||(n=jn(n)),n[Wn(n.length-1)];var e=tr(n)?En(n):jn(n),u=Y(e);r=Math.max(Math.min(r,u),0);for(var o=u-1,i=0;i1&&(e=Fn(e,r[1])),r=an(n)):(e=Pr,r=er(r,!1,!1),n=Object(n));for(var u=0,o=r.length;u1&&(t=r[1])):(r=jr(er(r,!1,!1),String),e=function(n,t){return!Mr(r,t)}),qr(n,e,t)}));function Wr(n,r,t){return i.call(n,0,Math.max(0,n.length-(null==r||t?1:r)))}function zr(n,r,t){return null==n||n.length<1?null==r||t?void 0:[]:null==r||t?n[0]:Wr(n,n.length-r)}function Lr(n,r,t){return i.call(n,null==r||t?1:r)}var Cr=j((function(n,r){return r=er(r,!0,!0),xr(n,(function(n){return!Mr(r,n)}))})),Kr=j((function(n,r){return Cr(n,r)}));function Jr(n,r,t,e){A(r)||(e=t,t=r,r=!1),null!=t&&(t=qn(t,e));for(var u=[],o=[],i=0,a=Y(n);ir?(e&&(clearTimeout(e),e=null),a=c,i=n.apply(u,o),e||(u=o=null)):e||!1===t.trailing||(e=setTimeout(f,l)),i};return c.cancel=function(){clearTimeout(e),a=0,e=u=o=null},c},debounce:function(n,r,t){var e,u,o=function(r,t){e=null,t&&(u=n.apply(r,t))},i=j((function(i){if(e&&clearTimeout(e),t){var a=!e;e=setTimeout(o,r),a&&(u=n.apply(this,i))}else e=or(o,r,this,i);return u}));return i.cancel=function(){clearTimeout(e),e=null},i},wrap:function(n,r){return nr(r,n)},negate:ar,compose:function(){var n=arguments,r=n.length-1;return function(){for(var t=r,e=n[r].apply(this,arguments);t--;)e=n[t].call(this,e);return e}},after:function(n,r){return function(){if(--n<1)return r.apply(this,arguments)}},before:fr,once:cr,findKey:lr,findIndex:pr,findLastIndex:vr,sortedIndex:hr,indexOf:gr,lastIndexOf:dr,find:br,detect:br,findWhere:function(n,r){return br(n,Dn(r))},each:mr,forEach:mr,map:jr,collect:jr,reduce:wr,foldl:wr,inject:wr,reduceRight:Ar,foldr:Ar,filter:xr,select:xr,reject:function(n,r,t){return xr(n,ar(qn(r)),t)},every:Sr,all:Sr,some:Or,any:Or,contains:Mr,includes:Mr,include:Mr,invoke:Er,pluck:Br,where:function(n,r){return xr(n,Dn(r))},max:Nr,min:function(n,r,t){var e,u,o=1/0,i=1/0;if(null==r||"number"==typeof r&&"object"!=typeof n[0]&&null!=n)for(var a=0,f=(n=tr(n)?n:jn(n)).length;ae||void 0===t)return 1;if(t - + - + Index — PyGromosTools documentation - - + + - - - - - - + + + + + + - - + + - + - + - + - +
- +
- +
- +
- - + + @@ -133,26 +133,26 @@
    - +
  • »
  • - +
  • Index
  • - - + +
  • - - - + + +
  • - +
- +
- +

Index

@@ -180,7 +180,7 @@

Index

| V | W | X - +

_

@@ -4322,7 +4322,7 @@

X

- + @@ -4350,7 +4350,7 @@

X

- + - - - - + + + + - \ No newline at end of file + diff --git a/docs/index.html b/docs/index.html index 6d4f42e7..c19d5ddc 100644 --- a/docs/index.html +++ b/docs/index.html @@ -4,67 +4,67 @@ - + - + Welcome to PyGromosTools — PyGromosTools documentation - - + + - - - - - - + + + + + + - - + + - + - + - + - +
- +
- +
- +
- - + + @@ -134,29 +134,29 @@
- +
- - + + \n", - "
\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
totenetotkintotpottotcovtotbondtotangletotimpropertotdihedraltotcrossdihedraltotnonbonded...totqmtotbsleustotrdcwip1wip2wip3wip4wip5wip6wip7
time
0.00-18707.183389001.643008-27708.82639201.6529180.083.47209031.35517386.8256560.0-27910.47931...0.00.00.00.00.00.00.00.00.00.0
0.02-21874.402259144.052649-31083.51961239.3537960.0105.44640841.72506392.1823240.0-31322.87341...0.00.00.00.00.00.00.00.00.00.0
0.04-23369.509439007.286580-32461.62635235.2724730.0115.92113233.05933086.2920110.0-32696.89882...0.00.00.00.00.00.00.00.00.00.0
0.06-24882.291378932.761094-33884.09921229.6042030.0114.66751331.04114583.8955450.0-34113.70341...0.00.00.00.00.00.00.00.00.00.0
0.08-26308.453708217.344364-34608.60906223.6664580.095.53131945.64514182.4899980.0-34832.27552...0.00.00.00.00.00.00.00.00.00.0
..................................................................
9.82-33984.049067228.953624-41213.00269262.3004920.0137.29592148.84298976.1615830.0-41475.30318...0.00.00.00.00.00.00.00.00.00.0
9.84-33968.587367232.753733-41201.34109237.3352170.0104.05189847.79358985.4897310.0-41438.67631...0.00.00.00.00.00.00.00.00.00.0
9.86-33984.236337232.380395-41216.61673258.5068680.0122.04992041.12041395.3365350.0-41475.12360...0.00.00.00.00.00.00.00.00.00.0
9.88-33971.511767158.715620-41130.22738240.8075180.0118.08776139.16555383.5542030.0-41371.03490...0.00.00.00.00.00.00.00.00.00.0
9.90-33941.429487178.210301-41119.63979245.0940240.0122.44382343.71280578.9373960.0-41364.73381...0.00.00.00.00.00.00.00.00.00.0
\n", - "

500 rows × 44 columns

\n", - "
" - ], - "text/plain": [ - " totene totkin totpot totcov totbond totangle \\\n", - "time \n", - "0.00 -18707.18338 9001.643008 -27708.82639 201.652918 0.0 83.472090 \n", - "0.02 -21874.40225 9144.052649 -31083.51961 239.353796 0.0 105.446408 \n", - "0.04 -23369.50943 9007.286580 -32461.62635 235.272473 0.0 115.921132 \n", - "0.06 -24882.29137 8932.761094 -33884.09921 229.604203 0.0 114.667513 \n", - "0.08 -26308.45370 8217.344364 -34608.60906 223.666458 0.0 95.531319 \n", - "... ... ... ... ... ... ... \n", - "9.82 -33984.04906 7228.953624 -41213.00269 262.300492 0.0 137.295921 \n", - "9.84 -33968.58736 7232.753733 -41201.34109 237.335217 0.0 104.051898 \n", - "9.86 -33984.23633 7232.380395 -41216.61673 258.506868 0.0 122.049920 \n", - "9.88 -33971.51176 7158.715620 -41130.22738 240.807518 0.0 118.087761 \n", - "9.90 -33941.42948 7178.210301 -41119.63979 245.094024 0.0 122.443823 \n", - "\n", - " totimproper totdihedral totcrossdihedral totnonbonded ... totqm \\\n", - "time ... \n", - "0.00 31.355173 86.825656 0.0 -27910.47931 ... 0.0 \n", - "0.02 41.725063 92.182324 0.0 -31322.87341 ... 0.0 \n", - "0.04 33.059330 86.292011 0.0 -32696.89882 ... 0.0 \n", - "0.06 31.041145 83.895545 0.0 -34113.70341 ... 0.0 \n", - "0.08 45.645141 82.489998 0.0 -34832.27552 ... 0.0 \n", - "... ... ... ... ... ... ... \n", - "9.82 48.842989 76.161583 0.0 -41475.30318 ... 0.0 \n", - "9.84 47.793589 85.489731 0.0 -41438.67631 ... 0.0 \n", - "9.86 41.120413 95.336535 0.0 -41475.12360 ... 0.0 \n", - "9.88 39.165553 83.554203 0.0 -41371.03490 ... 0.0 \n", - "9.90 43.712805 78.937396 0.0 -41364.73381 ... 0.0 \n", - "\n", - " totbsleus totrdc wip1 wip2 wip3 wip4 wip5 wip6 wip7 \n", - "time \n", - "0.00 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n", - "0.02 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n", - "0.04 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n", - "0.06 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n", - "0.08 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n", - "... ... ... ... ... ... ... ... ... ... \n", - "9.82 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n", - "9.84 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n", - "9.86 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n", - "9.88 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n", - "9.90 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n", - "\n", - "[500 rows x 44 columns]" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "tre.get_totals()" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "time\n", - "0.00 -18707.18338\n", - "0.02 -21874.40225\n", - "0.04 -23369.50943\n", - "0.06 -24882.29137\n", - "0.08 -26308.45370\n", - " ... \n", - "9.82 -33984.04906\n", - "9.84 -33968.58736\n", - "9.86 -33984.23633\n", - "9.88 -33971.51176\n", - "9.90 -33941.42948\n", - "Name: totene, Length: 500, dtype: float64" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "tre.get_totene()" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
numstates
time
0.000.0
0.020.0
0.040.0
0.060.0
0.080.0
......
9.820.0
9.840.0
9.860.0
9.880.0
9.900.0
\n", - "

500 rows × 1 columns

\n", - "
" - ], - "text/plain": [ - " numstates\n", - "time \n", - "0.00 0.0\n", - "0.02 0.0\n", - "0.04 0.0\n", - "0.06 0.0\n", - "0.08 0.0\n", - "... ...\n", - "9.82 0.0\n", - "9.84 0.0\n", - "9.86 0.0\n", - "9.88 0.0\n", - "9.90 0.0\n", - "\n", - "[500 rows x 1 columns]" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "tre.get_eds()" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
bath1bath2
time
0.00337.733853379.249510
0.02140.247591390.405454
0.04158.286787384.054332
0.06194.417399379.924943
0.08148.085196350.279078
.........
9.82309.897586303.580973
9.84333.245070303.151191
9.86281.230117304.457362
9.88303.331346300.721693
9.90292.611534301.834125
\n", - "

500 rows × 2 columns

\n", - "
" - ], - "text/plain": [ - " bath1 bath2\n", - "time \n", - "0.00 337.733853 379.249510\n", - "0.02 140.247591 390.405454\n", - "0.04 158.286787 384.054332\n", - "0.06 194.417399 379.924943\n", - "0.08 148.085196 350.279078\n", - "... ... ...\n", - "9.82 309.897586 303.580973\n", - "9.84 333.245070 303.151191\n", - "9.86 281.230117 304.457362\n", - "9.88 303.331346 300.721693\n", - "9.90 292.611534 301.834125\n", - "\n", - "[500 rows x 2 columns]" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "tre.get_temperature()" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{1: {1: Lennard-Jones Coulomb/RF lattice sum real lattice sum reciproc\n", - " 0 -49.758195 -762.060450 0.0 0.0\n", - " 1 -43.154466 -764.352469 0.0 0.0\n", - " 2 -55.276034 -752.245283 0.0 0.0\n", - " 3 -72.339265 -748.238168 0.0 0.0\n", - " 4 -71.978272 -750.589374 0.0 0.0\n", - " .. ... ... ... ...\n", - " 495 -64.534736 -692.601669 0.0 0.0\n", - " 496 -65.225064 -689.890251 0.0 0.0\n", - " 497 -73.093945 -684.754692 0.0 0.0\n", - " 498 -71.722587 -682.870949 0.0 0.0\n", - " 499 -76.396290 -691.180471 0.0 0.0\n", - " \n", - " [500 rows x 4 columns],\n", - " 2: Lennard-Jones Coulomb/RF lattice sum real lattice sum reciproc\n", - " 0 224.745840 -1403.049610 0.0 0.0\n", - " 1 139.876765 -1596.589252 0.0 0.0\n", - " 2 10.984995 -1599.595653 0.0 0.0\n", - " 3 -44.054829 -1538.188033 0.0 0.0\n", - " 4 -66.815225 -1539.819765 0.0 0.0\n", - " .. ... ... ... ...\n", - " 495 -42.655965 -2003.156089 0.0 0.0\n", - " 496 -53.759785 -1975.988906 0.0 0.0\n", - " 497 -63.511509 -1996.317923 0.0 0.0\n", - " 498 -31.412004 -1891.400958 0.0 0.0\n", - " 499 -9.502844 -1931.478907 0.0 0.0\n", - " \n", - " [500 rows x 4 columns]},\n", - " 2: {1: Lennard-Jones Coulomb/RF lattice sum real lattice sum reciproc\n", - " 0 224.745840 -1403.049610 0.0 0.0\n", - " 1 139.876765 -1596.589252 0.0 0.0\n", - " 2 10.984995 -1599.595653 0.0 0.0\n", - " 3 -44.054829 -1538.188033 0.0 0.0\n", - " 4 -66.815225 -1539.819765 0.0 0.0\n", - " .. ... ... ... ...\n", - " 495 -42.655965 -2003.156089 0.0 0.0\n", - " 496 -53.759785 -1975.988906 0.0 0.0\n", - " 497 -63.511509 -1996.317923 0.0 0.0\n", - " 498 -31.412004 -1891.400958 0.0 0.0\n", - " 499 -9.502844 -1931.478907 0.0 0.0\n", - " \n", - " [500 rows x 4 columns],\n", - " 2: Lennard-Jones Coulomb/RF lattice sum real lattice sum reciproc\n", - " 0 3334.225340 -29254.58223 0.0 0.0\n", - " 1 3827.456046 -32886.11003 0.0 0.0\n", - " 2 3887.747212 -34188.51406 0.0 0.0\n", - " 3 3920.285672 -35631.16879 0.0 0.0\n", - " 4 4186.175207 -36589.24809 0.0 0.0\n", - " .. ... ... ... ...\n", - " 495 6940.508960 -45612.86368 0.0 0.0\n", - " 496 6843.725667 -45497.53797 0.0 0.0\n", - " 497 6668.136669 -45325.58220 0.0 0.0\n", - " 498 6651.685025 -45345.31343 0.0 0.0\n", - " 499 6509.567522 -45165.74282 0.0 0.0\n", - " \n", - " [500 rows x 4 columns]}}" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "tre.get_nonbondedContributions()" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{0: bond angle improper dihedral crossdihedral\n", - " time \n", - " 0.00 0.0 83.472090 31.355173 86.825656 0.0\n", - " 0.02 0.0 105.446408 41.725063 92.182324 0.0\n", - " 0.04 0.0 115.921132 33.059330 86.292011 0.0\n", - " 0.06 0.0 114.667513 31.041145 83.895545 0.0\n", - " 0.08 0.0 95.531319 45.645141 82.489998 0.0\n", - " ... ... ... ... ... ...\n", - " 9.82 0.0 137.295921 48.842989 76.161583 0.0\n", - " 9.84 0.0 104.051898 47.793589 85.489731 0.0\n", - " 9.86 0.0 122.049920 41.120413 95.336535 0.0\n", - " 9.88 0.0 118.087761 39.165553 83.554203 0.0\n", - " 9.90 0.0 122.443823 43.712805 78.937396 0.0\n", - " \n", - " [500 rows x 5 columns],\n", - " 1: bond angle improper dihedral crossdihedral\n", - " time \n", - " 0.00 0.0 0.0 0.0 0.0 0.0\n", - " 0.02 0.0 0.0 0.0 0.0 0.0\n", - " 0.04 0.0 0.0 0.0 0.0 0.0\n", - " 0.06 0.0 0.0 0.0 0.0 0.0\n", - " 0.08 0.0 0.0 0.0 0.0 0.0\n", - " ... ... ... ... ... ...\n", - " 9.82 0.0 0.0 0.0 0.0 0.0\n", - " 9.84 0.0 0.0 0.0 0.0 0.0\n", - " 9.86 0.0 0.0 0.0 0.0 0.0\n", - " 9.88 0.0 0.0 0.0 0.0 0.0\n", - " 9.90 0.0 0.0 0.0 0.0 0.0\n", - " \n", - " [500 rows x 5 columns]}" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "tre.get_bondedContributions()" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{0: constraints pos. restraints dist. restraints disfield res \\\n", - " time \n", - " 0.00 0.0 2.187595e-29 0.0 0.0 \n", - " 0.02 0.0 6.506471e+01 0.0 0.0 \n", - " 0.04 0.0 8.483034e+01 0.0 0.0 \n", - " 0.06 0.0 6.904674e+01 0.0 0.0 \n", - " 0.08 0.0 8.281099e+01 0.0 0.0 \n", - " ... ... ... ... ... \n", - " 9.82 0.0 0.000000e+00 0.0 0.0 \n", - " 9.84 0.0 0.000000e+00 0.0 0.0 \n", - " 9.86 0.0 0.000000e+00 0.0 0.0 \n", - " 9.88 0.0 0.000000e+00 0.0 0.0 \n", - " 9.90 0.0 0.000000e+00 0.0 0.0 \n", - " \n", - " dihe. restr. SASA SASA volume jvalue rdc local elevation \\\n", - " time \n", - " 0.00 0.0 0.0 0.0 0.0 0.0 0.0 \n", - " 0.02 0.0 0.0 0.0 0.0 0.0 0.0 \n", - " 0.04 0.0 0.0 0.0 0.0 0.0 0.0 \n", - " 0.06 0.0 0.0 0.0 0.0 0.0 0.0 \n", - " 0.08 0.0 0.0 0.0 0.0 0.0 0.0 \n", - " ... ... ... ... ... ... ... \n", - " 9.82 0.0 0.0 0.0 0.0 0.0 0.0 \n", - " 9.84 0.0 0.0 0.0 0.0 0.0 0.0 \n", - " 9.86 0.0 0.0 0.0 0.0 0.0 0.0 \n", - " 9.88 0.0 0.0 0.0 0.0 0.0 0.0 \n", - " 9.90 0.0 0.0 0.0 0.0 0.0 0.0 \n", - " \n", - " path integral angle restraint \n", - " time \n", - " 0.00 0.0 0.0 \n", - " 0.02 0.0 0.0 \n", - " 0.04 0.0 0.0 \n", - " 0.06 0.0 0.0 \n", - " 0.08 0.0 0.0 \n", - " ... ... ... \n", - " 9.82 0.0 0.0 \n", - " 9.84 0.0 0.0 \n", - " 9.86 0.0 0.0 \n", - " 9.88 0.0 0.0 \n", - " 9.90 0.0 0.0 \n", - " \n", - " [500 rows x 12 columns],\n", - " 1: constraints pos. restraints dist. restraints disfield res \\\n", - " time \n", - " 0.00 0.0 0.0 0.0 0.0 \n", - " 0.02 0.0 0.0 0.0 0.0 \n", - " 0.04 0.0 0.0 0.0 0.0 \n", - " 0.06 0.0 0.0 0.0 0.0 \n", - " 0.08 0.0 0.0 0.0 0.0 \n", - " ... ... ... ... ... \n", - " 9.82 0.0 0.0 0.0 0.0 \n", - " 9.84 0.0 0.0 0.0 0.0 \n", - " 9.86 0.0 0.0 0.0 0.0 \n", - " 9.88 0.0 0.0 0.0 0.0 \n", - " 9.90 0.0 0.0 0.0 0.0 \n", - " \n", - " dihe. restr. SASA SASA volume jvalue rdc local elevation \\\n", - " time \n", - " 0.00 0.0 0.0 0.0 0.0 0.0 0.0 \n", - " 0.02 0.0 0.0 0.0 0.0 0.0 0.0 \n", - " 0.04 0.0 0.0 0.0 0.0 0.0 0.0 \n", - " 0.06 0.0 0.0 0.0 0.0 0.0 0.0 \n", - " 0.08 0.0 0.0 0.0 0.0 0.0 0.0 \n", - " ... ... ... ... ... ... ... \n", - " 9.82 0.0 0.0 0.0 0.0 0.0 0.0 \n", - " 9.84 0.0 0.0 0.0 0.0 0.0 0.0 \n", - " 9.86 0.0 0.0 0.0 0.0 0.0 0.0 \n", - " 9.88 0.0 0.0 0.0 0.0 0.0 0.0 \n", - " 9.90 0.0 0.0 0.0 0.0 0.0 0.0 \n", - " \n", - " path integral angle restraint \n", - " time \n", - " 0.00 0.0 0.0 \n", - " 0.02 0.0 0.0 \n", - " 0.04 0.0 0.0 \n", - " 0.06 0.0 0.0 \n", - " 0.08 0.0 0.0 \n", - " ... ... ... \n", - " 9.82 0.0 0.0 \n", - " 9.84 0.0 0.0 \n", - " 9.86 0.0 0.0 \n", - " 9.88 0.0 0.0 \n", - " 9.90 0.0 0.0 \n", - " \n", - " [500 rows x 12 columns]}" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "tre.get_specialContributions()" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{0: kinetic total centre of mass internal/rotational\n", - " time \n", - " 0.00 199.267678 1.727293 197.540386\n", - " 0.02 82.748033 3.733777 79.014255\n", - " 0.04 93.391409 13.269526 80.121884\n", - " 0.06 114.708974 19.291389 95.417585\n", - " 0.08 87.372329 4.900502 82.471827\n", - " ... ... ... ...\n", - " 9.82 182.843894 1.015354 181.828540\n", - " 9.84 196.619234 1.850293 194.768941\n", - " 9.86 165.929687 2.300111 163.629576\n", - " 9.88 178.969720 2.349578 176.620143\n", - " 9.90 172.644882 1.280250 171.364632\n", - " \n", - " [500 rows x 3 columns],\n", - " 1: kinetic total centre of mass internal/rotational\n", - " time \n", - " 0.00 8802.375330 3562.845539 5239.529791\n", - " 0.02 9061.304617 3577.227299 5484.077318\n", - " 0.04 8913.895170 3800.411509 5113.483661\n", - " 0.06 8818.052120 3988.916527 4829.135594\n", - " 0.08 8129.972035 3728.700202 4401.271834\n", - " ... ... ... ...\n", - " 9.82 7046.109730 3465.136252 3580.973478\n", - " 9.84 7036.134499 3485.663302 3550.471197\n", - " 9.86 7066.450708 3447.385902 3619.064807\n", - " 9.88 6979.745899 3399.347111 3580.398789\n", - " 9.90 7005.565419 3460.613030 3544.952389\n", - " \n", - " [500 rows x 3 columns]}" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "tre.get_baths()" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "time\n", - "0.00 17520.0632\n", - "0.02 17520.0632\n", - "0.04 17520.0632\n", - "0.06 17520.0632\n", - "0.08 17520.0632\n", - " ... \n", - "9.82 17520.0632\n", - "9.84 17520.0632\n", - "9.86 17520.0632\n", - "9.88 17520.0632\n", - "9.90 17520.0632\n", - "Name: mass, Length: 500, dtype: float64" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "tre.get_mass()" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{0: total com ir scaling factor\n", - " time \n", - " 0.00 337.733853 138.497941 341.853205 0.991391\n", - " 0.02 140.247591 299.382024 136.737996 0.994159\n", - " 0.04 158.286787 1063.978128 138.654801 0.993850\n", - " 0.06 194.417399 1546.823663 165.124752 0.993007\n", - " 0.08 148.085196 392.932396 142.721491 0.993996\n", - " ... ... ... ... ...\n", - " 9.82 309.897586 81.413164 314.663095 0.999653\n", - " 9.84 333.245070 148.360330 337.057086 0.998660\n", - " 9.86 281.230117 184.427645 283.168907 1.000526\n", - " 9.88 303.331346 188.394011 305.649712 0.999951\n", - " 9.90 292.611534 102.653130 296.554795 1.000165\n", - " \n", - " [500 rows x 4 columns],\n", - " 1: total com ir scaling factor\n", - " time \n", - " 0.00 379.249510 306.848933 451.252829 0.991281\n", - " 0.02 390.405454 308.087558 472.314406 0.991514\n", - " 0.04 384.054332 327.309227 440.397146 0.991531\n", - " 0.06 379.924943 343.544161 415.907760 0.991543\n", - " 0.08 350.279078 321.133113 379.058130 0.991669\n", - " ... ... ... ... ...\n", - " 9.82 303.580973 298.433752 308.410196 0.999889\n", - " 9.84 303.151191 300.201638 305.783197 0.999906\n", - " 9.86 304.457362 296.905009 311.690800 0.999819\n", - " 9.88 300.721693 292.767683 308.360701 0.999954\n", - " 9.90 301.834125 298.044191 305.307891 0.999955\n", - " \n", - " [500 rows x 4 columns]}" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "tre.get_temperature_Info()" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "0 [29.15461327, 3.077767162, 0.0, 0.0, 0.0, 3.07...\n", - "1 [29.28876143, 3.082480483, 0.0, 0.0, 0.0, 3.08...\n", - "2 [29.37780902, 3.085601245, 0.0, 0.0, 0.0, 3.08...\n", - "3 [29.41603182, 3.086938867, 0.0, 0.0, 0.0, 3.08...\n", - "4 [29.43162103, 3.087484085, 0.0, 0.0, 0.0, 3.08...\n", - " ... \n", - "495 [29.39845332, 3.086323844, 0.0, 0.0, 0.0, 3.08...\n", - "496 [29.41082298, 3.08675665, 0.0, 0.0, 0.0, 3.086...\n", - "497 [29.40716665, 3.08662873, 0.0, 0.0, 0.0, 3.086...\n", - "498 [29.40436699, 3.086530774, 0.0, 0.0, 0.0, 3.08...\n", - "499 [29.39948681, 3.08636001, 0.0, 0.0, 0.0, 3.086...\n", - "Name: volume, Length: 500, dtype: object" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "tre.database.volume" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "0 [297.887613, -3148.182254, 1194.216824, 302.56...\n", - "1 [197.1301975, -1692.558634, 1194.291028, 177.3...\n", - "2 [111.5259605, -371.0934792, 1267.100705, 109.4...\n", - "3 [41.56182794, 726.7777861, 1338.069813, 89.317...\n", - "4 [27.24401339, 849.9571924, 1250.874931, 43.676...\n", - " ... \n", - "495 [27.33996666, 755.2665619, 1157.142929, 21.727...\n", - "496 [11.46965788, 993.9435962, 1162.609635, 16.641...\n", - "497 [-9.862440994, 1299.59988, 1154.586657, 5.2558...\n", - "498 [-2.744620472, 1172.469946, 1132.118032, -10.0...\n", - "499 [-9.971009562, 1304.005586, 1157.434304, -14.4...\n", - "Name: pressure, Length: 500, dtype: object" - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "tre.database.pressure" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "time\n", - "0.00 997.878076\n", - "0.02 993.307603\n", - "0.04 990.296771\n", - "0.06 989.009992\n", - "0.08 988.486138\n", - " ... \n", - "9.82 989.601361\n", - "9.84 989.185152\n", - "9.86 989.308142\n", - "9.88 989.402336\n", - "9.90 989.566573\n", - "Name: density, Length: 500, dtype: float64" - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "tre.get_density()" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
bath1bath2
time
0.00337.733853379.249510
0.02140.247591390.405454
0.04158.286787384.054332
0.06194.417399379.924943
0.08148.085196350.279078
.........
9.82309.897586303.580973
9.84333.245070303.151191
9.86281.230117304.457362
9.88303.331346300.721693
9.90292.611534301.834125
\n", - "

500 rows × 2 columns

\n", - "
" - ], - "text/plain": [ - " bath1 bath2\n", - "time \n", - "0.00 337.733853 379.249510\n", - "0.02 140.247591 390.405454\n", - "0.04 158.286787 384.054332\n", - "0.06 194.417399 379.924943\n", - "0.08 148.085196 350.279078\n", - "... ... ...\n", - "9.82 309.897586 303.580973\n", - "9.84 333.245070 303.151191\n", - "9.86 281.230117 304.457362\n", - "9.88 303.331346 300.721693\n", - "9.90 292.611534 301.834125\n", - "\n", - "[500 rows x 2 columns]" - ] - }, - "execution_count": 28, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "tre.get_temperature()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "interpreter": { - "hash": "ea5b7c5009fd10d704f0659c781e736412420b87d02c84beb20109b03098a3d1" - }, - "kernelspec": { - "display_name": "Python 3.9.10 ('PyGrom3')", - "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.9.10" - }, - "orig_nbformat": 4 - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/examples/dev/test copy.ipynb b/examples/dev/test copy.ipynb index d1bee5d6..563ea46d 100644 --- a/examples/dev/test copy.ipynb +++ b/examples/dev/test copy.ipynb @@ -245,4 +245,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} \ No newline at end of file +} diff --git a/examples/dev/test.ipynb b/examples/dev/test.ipynb index aa71a4be..e4611c9c 100644 --- a/examples/dev/test.ipynb +++ b/examples/dev/test.ipynb @@ -864,4 +864,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} \ No newline at end of file +} diff --git a/examples/dev/test_smirnoff.ipynb b/examples/dev/test_smirnoff.ipynb index ec57cff8..8c4674e3 100644 --- a/examples/dev/test_smirnoff.ipynb +++ b/examples/dev/test_smirnoff.ipynb @@ -918,4 +918,4 @@ "source": [] } ] -} \ No newline at end of file +} diff --git a/examples/example_files/MD_Simulation/MD_input/md.cnf b/examples/example_files/MD_Simulation/MD_input/md.cnf index e2f130fc..c365da49 100644 --- a/examples/example_files/MD_Simulation/MD_input/md.cnf +++ b/examples/example_files/MD_Simulation/MD_input/md.cnf @@ -11,7 +11,7 @@ electrostatic potential >>> line_seperator: '\n' field_seperator: '\t' comments_char: '#' END POSITION -# +# 1 VAL H1 1 -0.466039509 0.107068229 -0.151069220 1 VAL H2 2 -0.401465786 0.026940681 -0.024813902 1 VAL N 3 -0.432414924 0.018324392 -0.119519889 diff --git a/examples/example_files/MD_Simulation/MD_input/md.imd b/examples/example_files/MD_Simulation/MD_input/md.imd index d527c975..32009f38 100644 --- a/examples/example_files/MD_Simulation/MD_input/md.imd +++ b/examples/example_files/MD_Simulation/MD_input/md.imd @@ -6,65 +6,65 @@ steepest descent energy minimization of the peptide in water END BOUNDCOND # NTB NDFMIN - 1 3 + 1 3 END CONSTRAINT # NTC - 3 + 3 # NTCP NTCP0(1) - 1 0.000100 + 1 0.000100 # NTCS NTCS0(1) - 1 0.000100 + 1 0.000100 END ENERGYMIN # NTEM NCYC DELE DX0 DXM NMIN FLIM - 1 0 0.1 0.01 0.05 2000 0.0 + 1 0 0.1 0.01 0.05 2000 0.0 END FORCE # BONDS ANGLES IMPROPER DIHEDRAL ELECTROSTATIC VDW - 1 1 1 1 1 1 + 1 1 1 1 1 1 # NEGR NRE - 4 71 72 73 2863 + 4 71 72 73 2863 END INITIALISE # NTIVEL NTISHK NTINHT NTINHB - 0 0 0 0 + 0 0 0 0 # NTISHI NTIRTC NTICOM - 1 0 0 + 1 0 0 # NTISTI - 0 + 0 # IG TEMPI - 210185 300.0 + 210185 300.0 END NONBONDED # NLRELE - 1 + 1 # APPAK RCRF EPSRF NSLFEXCL - 0.0 1.4 61 1 + 0.0 1.4 61 1 # NSHAPE ASHAPE NA2CLC TOLA2 EPSLS - -1 1.4 2 1e-10 0 + -1 1.4 2 1e-10 0 # NKX NKY NKZ KCUT - 10 10 10 100 + 10 10 10 100 # NGX NGY NGZ NASORD NFDORD NALIAS NSPORD - 32 32 32 3 2 3 4 + 32 32 32 3 2 3 4 # NQEVAL FACCUR NRDGRD NWRGRD - 100000 1.6 0 0 + 100000 1.6 0 0 # NLRLJ SLVDNS - 0 33.3 + 0 33.3 END PAIRLIST # ALGORITHM NSNB RCUTP RCUTL SIZE TYPE - 0 5 0.800000 1.400000 0.4 0 + 0 5 0.800000 1.400000 0.4 0 END PRINTOUT # NTPR NTPP - 300 0 + 300 0 END STEP # NSTLIM T DT - 3000 0.000000 0.002000 + 3000 0.000000 0.002000 END SYSTEM # NPM NSM - 1 930 + 1 930 END diff --git a/examples/example_files/MD_Simulation/MD_input/md.pos b/examples/example_files/MD_Simulation/MD_input/md.pos index d489da6d..5052f9e7 100644 --- a/examples/example_files/MD_Simulation/MD_input/md.pos +++ b/examples/example_files/MD_Simulation/MD_input/md.pos @@ -11,7 +11,7 @@ electrostatic potential >>> line_seperator: '\n' field_seperator: '\t' comments_char: '#' END POSRESSPEC -# +# 1 VAL H1 1 -0.466039509 0.107068229 -0.151069220 1 VAL H2 2 -0.401465786 0.026940681 -0.024813902 1 VAL N 3 -0.432414924 0.018324392 -0.119519889 diff --git a/examples/example_files/MD_Simulation/MD_input/md.rpf b/examples/example_files/MD_Simulation/MD_input/md.rpf index b805c2ff..5dc82973 100644 --- a/examples/example_files/MD_Simulation/MD_input/md.rpf +++ b/examples/example_files/MD_Simulation/MD_input/md.rpf @@ -11,7 +11,7 @@ electrostatic potential >>> line_seperator: '\n' field_seperator: '\t' comments_char: '#' END REFPOSITION -# +# 1 VAL H1 1 -0.466039509 0.107068229 -0.151069220 1 VAL H2 2 -0.401465786 0.026940681 -0.024813902 1 VAL N 3 -0.432414924 0.018324392 -0.119519889 diff --git a/examples/example_files/MD_Simulation/MD_input/md.top b/examples/example_files/MD_Simulation/MD_input/md.top index 5b7bbade..fe96ee46 100644 --- a/examples/example_files/MD_Simulation/MD_input/md.top +++ b/examples/example_files/MD_Simulation/MD_input/md.top @@ -110,7 +110,7 @@ SOLUTEATOM 4 1 H3 21 1.008 0.248 0 1 5 2 6 9 5 1 CA 14 13.019 0.127 1 6 6 7 8 9 10 11 - + 2 12 13 6 1 CB 14 13.019 0.0 0 3 7 8 9 2 10 11 @@ -140,7 +140,7 @@ SOLUTEATOM 17 2 HD1 20 1.008 0.14 1 4 18 20 21 24 0 18 2 CD2 12 12.011 -0.14 0 6 19 20 22 23 24 25 - + 0 19 2 HD2 20 1.008 0.14 1 3 22 23 24 0 @@ -179,7 +179,7 @@ SOLUTEATOM 36 3 HE 21 1.008 0.24 0 1 37 2 38 41 37 3 CZ 12 12.011 0.34 0 6 38 39 40 41 42 43 - + 0 38 3 NH1 10 14.0067 -0.26 0 3 39 40 41 2 42 43 @@ -2234,7 +2234,7 @@ PRESSUREGROUPS 71 72 73 END LJEXCEPTIONS -# This block defines special LJ-interactions based on atom numbers +# This block defines special LJ-interactions based on atom numbers # This overrules the normal LJ-parameters (including 1-4 interactions) # NEX: number of exceptions 0 diff --git a/examples/example_files/QMMM_files/md.imd b/examples/example_files/QMMM_files/md.imd index 9ca4603d..3898f1a0 100644 --- a/examples/example_files/QMMM_files/md.imd +++ b/examples/example_files/QMMM_files/md.imd @@ -1,37 +1,37 @@ TITLE - >>> Generated with PyGromosTools (riniker group) <<< + >>> Generated with PyGromosTools (riniker group) <<< END BOUNDCOND # NTB NDFMIN - 1 3 + 1 3 END COMTRANSROT # NSCM - 1000 + 1000 END CONSTRAINT # NTC - 3 + 3 # NTCP NTCP0(1) - 1 0.000100 + 1 0.000100 # NTCS NTCS0(1) - 1 0.000100 + 1 0.000100 END FORCE # BONDS ANGLES IMPROPER DIHEDRAL ELECTROSTATIC VDW - 0 1 1 1 1 1 + 0 1 1 1 1 1 # NEGR NRE - 1 3613 + 1 3613 END INITIALISE # NTIVEL NTISHK NTINHT NTINHB - 1 3 0 0 + 1 3 0 0 # NTISHI NTIRTC NTICOM - 1 0 0 + 1 0 0 # NTISTI - 0 + 0 # IG TEMPI - 210185 298.000000 + 210185 298.000000 END MULTIBATH # ALGORITHM @@ -47,49 +47,49 @@ MULTIBATH END NONBONDED # NLRELE - 1 + 1 # APPAK RCRF EPSRF NSLFEXCL - 0.000000 1.400000 66.700000 1 + 0.000000 1.400000 66.700000 1 # NSHAPE ASHAPE NA2CLC TOLA2 EPSLS - 3 1.400000 2 1e-10 0.000000 + 3 1.400000 2 1e-10 0.000000 # NKX NKY NKZ KCUT - 10 10 10 100.000000 + 10 10 10 100.000000 # NGX NGY NGZ NASORD NFDORD NALIAS NSPORD - 32 32 32 3 2 3 4 + 32 32 32 3 2 3 4 # NQEVAL FACCUR NRDGRD NWRGRD - 1000 1.600000 0 0 + 1000 1.600000 0 0 # NLRLJ SLVDNS - 0 33.300000 + 0 33.300000 END PAIRLIST # ALGORITHM NSNB RCUTP RCUTL SIZE TYPE - 0 5 0.800000 1.400000 0.4 0 + 0 5 0.800000 1.400000 0.4 0 END PRESSURESCALE # COUPLE SCALE COMP TAUP VIRIAL - 2 1 0.000458 0.500000 2 + 2 1 0.000458 0.500000 2 # SEMIANISOTROPIC COUPLINGS(X, Y, Z) - 1 1 1 + 1 1 1 # PRES0(1...3,1...3) 0.06102 0.0 0.0 0.0 0.06102 0.0 - 0.0 0.0 0.06102 + 0.0 0.0 0.06102 END PRINTOUT # NTPR NTPP - 10 0 + 10 0 END STEP # NSTLIM T DT - 100000 0.000000 0.002000 + 100000 0.000000 0.002000 END SYSTEM # NPM NSM - 1 0 + 1 0 END WRITETRAJ # NTWX NTWSE NTWV NTWF NTWE NTWG NTWB - 200 0 0 0 100 0 0 + 200 0 0 0 100 0 0 END QMMM # NTQMMM NTQMSW RCUTQ NTWQMMM QMLJ MMSCAL diff --git a/examples/example_files/QMMM_files/menthol-methanol-dmf-eq.imd b/examples/example_files/QMMM_files/menthol-methanol-dmf-eq.imd index 0528bb2b..bc1e460c 100644 --- a/examples/example_files/QMMM_files/menthol-methanol-dmf-eq.imd +++ b/examples/example_files/QMMM_files/menthol-methanol-dmf-eq.imd @@ -4,35 +4,35 @@ TITLE Author: Felix Pultar Date: February, 14 2022 - >>> Generated with PyGromosTools (riniker group) <<< + >>> Generated with PyGromosTools (riniker group) <<< END BOUNDCOND # NTB NDFMIN - 1 3 + 1 3 END CONSTRAINT # NTC - 3 + 3 # NTCP NTCP0(1) - 1 0.000100 + 1 0.000100 # NTCS NTCS0(1) - 1 0.000100 + 1 0.000100 END FORCE # BONDS ANGLES IMPROPER DIHEDRAL ELECTROSTATIC VDW - 0 1 1 1 1 1 + 0 1 1 1 1 1 # NEGR NRE - 2 31 1951 + 2 31 1951 END INITIALISE # NTIVEL NTISHK NTINHT NTINHB - 0 0 0 0 + 0 0 0 0 # NTISHI NTIRTC NTICOM - 1 0 0 + 1 0 0 # NTISTI - 0 + 0 # IG TEMPI - 210185 400.000000 + 210185 400.000000 END MULTIBATH # ALGORITHM @@ -50,47 +50,47 @@ MULTIBATH END NONBONDED # NLRELE - 1 + 1 # APPAK RCRF EPSRF NSLFEXCL - 0.000000 1.400000 35.600000 1 + 0.000000 1.400000 35.600000 1 # NSHAPE ASHAPE NA2CLC TOLA2 EPSLS - -1 1.400000 2 1e-10 0.000000 + -1 1.400000 2 1e-10 0.000000 # NKX NKY NKZ KCUT - 10 10 10 100.000000 + 10 10 10 100.000000 # NGX NGY NGZ NASORD NFDORD NALIAS NSPORD - 32 32 32 3 2 3 4 + 32 32 32 3 2 3 4 # NQEVAL FACCUR NRDGRD NWRGRD - 100000 1.600000 0 0 + 100000 1.600000 0 0 # NLRLJ SLVDNS - 0 33.300000 + 0 33.300000 END PAIRLIST # ALGORITHM NSNB RCUTP RCUTL SIZE TYPE - 0 5 0.800000 1.400000 0.4 0 + 0 5 0.800000 1.400000 0.4 0 END PRESSURESCALE # COUPLE SCALE COMP TAUP VIRIAL - 2 1 0.000458 0.500000 2 + 2 1 0.000458 0.500000 2 # SEMIANISOTROPIC COUPLINGS(X, Y, Z) - 1 1 1 + 1 1 1 # PRES0(1...3,1...3) 0.097629 0.0 0.0 0.0 0.097629 0.0 - 0.0 0.0 0.097629 + 0.0 0.0 0.097629 END PRINTOUT # NTPR NTPP - 10 0 + 10 0 END STEP # NSTLIM T DT - 2500 0.000000 0.000500 + 2500 0.000000 0.000500 END SYSTEM # NPM NSM - 1 0 + 1 0 END WRITETRAJ # NTWX NTWSE NTWV NTWF NTWE NTWG NTWB - 1 0 0 0 1 0 0 + 1 0 0 0 1 0 0 END diff --git a/examples/example_files/QMMM_files/menthol-methanol-dmf.qmmm b/examples/example_files/QMMM_files/menthol-methanol-dmf.qmmm index b48cae90..dd276339 100644 --- a/examples/example_files/QMMM_files/menthol-methanol-dmf.qmmm +++ b/examples/example_files/QMMM_files/menthol-methanol-dmf.qmmm @@ -36,7 +36,7 @@ O 30 8 0 H 31 1 0 END QMUNIT -# QLGL QEGE QCGC QIGI +# QLGL QEGE QCGC QIGI 5.2918E-2 2625.50 1.0 0.1 END XTBELEMENTS diff --git a/examples/example_files/QMMM_files/menthol-methanol-dmf/menthol-methanol-dmf.cnf b/examples/example_files/QMMM_files/menthol-methanol-dmf/menthol-methanol-dmf.cnf index dc436e8a..582f29d2 100644 --- a/examples/example_files/QMMM_files/menthol-methanol-dmf/menthol-methanol-dmf.cnf +++ b/examples/example_files/QMMM_files/menthol-methanol-dmf/menthol-methanol-dmf.cnf @@ -1,10 +1,10 @@ TITLE - >>> Generated with PyGromosTools (riniker group) <<< + >>> Generated with PyGromosTools (riniker group) <<< END POSITION -# +# 1 0RHW H18 1 3.009460861 0.585481834 1.244120718 1 0RHW C9 2 2.912350728 0.627343262 1.215241152 1 0RHW H16 3 2.928516209 0.731345485 1.184382826 @@ -1958,7 +1958,7 @@ POSITION 261 ERI7 H7 1951 1.390804011 0.893078167 0.565670204 END VELOCITY -# +# 1 0RHW H18 1 0.000000000 0.000000000 0.000000000 1 0RHW C9 2 0.000000000 0.000000000 0.000000000 1 0RHW H16 3 0.000000000 0.000000000 0.000000000 diff --git a/examples/example_files/QMMM_files/menthol-methanol-dmf/menthol-methanol-dmf.imd b/examples/example_files/QMMM_files/menthol-methanol-dmf/menthol-methanol-dmf.imd index 78101838..f46a91e4 100644 --- a/examples/example_files/QMMM_files/menthol-methanol-dmf/menthol-methanol-dmf.imd +++ b/examples/example_files/QMMM_files/menthol-methanol-dmf/menthol-methanol-dmf.imd @@ -1,38 +1,38 @@ TITLE Demonstration of a Gromos imd file containing a QMMM block - >>> Generated with PyGromosTools (riniker group) <<< + >>> Generated with PyGromosTools (riniker group) <<< END BOUNDCOND # NTB NDFMIN - 1 3 + 1 3 END COMTRANSROT # NSCM - 1000 + 1000 END CONSTRAINT # NTC - 3 + 3 # NTCP NTCP0(1) - 1 0.000100 + 1 0.000100 # NTCS NTCS0(1) - 1 0.000100 + 1 0.000100 END FORCE # BONDS ANGLES IMPROPER DIHEDRAL ELECTROSTATIC VDW - 0 1 1 1 1 1 + 0 1 1 1 1 1 # NEGR NRE - 1 1951 + 1 1951 END INITIALISE # NTIVEL NTISHK NTINHT NTINHB - 1 3 0 0 + 1 3 0 0 # NTISHI NTIRTC NTICOM - 1 0 0 + 1 0 0 # NTISTI - 0 + 0 # IG TEMPI - 210185 298.000000 + 210185 298.000000 END MULTIBATH # ALGORITHM @@ -48,51 +48,51 @@ MULTIBATH END NONBONDED # NLRELE - 1 + 1 # APPAK RCRF EPSRF NSLFEXCL - 0.000000 1.400000 66.700000 1 + 0.000000 1.400000 66.700000 1 # NSHAPE ASHAPE NA2CLC TOLA2 EPSLS - 3 1.400000 2 1e-10 0.000000 + 3 1.400000 2 1e-10 0.000000 # NKX NKY NKZ KCUT - 10 10 10 100.000000 + 10 10 10 100.000000 # NGX NGY NGZ NASORD NFDORD NALIAS NSPORD - 32 32 32 3 2 3 4 + 32 32 32 3 2 3 4 # NQEVAL FACCUR NRDGRD NWRGRD - 1000 1.600000 0 0 + 1000 1.600000 0 0 # NLRLJ SLVDNS - 0 33.300000 + 0 33.300000 END PAIRLIST # ALGORITHM NSNB RCUTP RCUTL SIZE TYPE - 0 5 0.800000 1.400000 0.4 0 + 0 5 0.800000 1.400000 0.4 0 END PRESSURESCALE # COUPLE SCALE COMP TAUP VIRIAL - 2 1 0.000458 0.500000 2 + 2 1 0.000458 0.500000 2 # SEMIANISOTROPIC COUPLINGS(X, Y, Z) - 1 1 1 + 1 1 1 # PRES0(1...3,1...3) 0.06102 0.0 0.0 0.0 0.06102 0.0 - 0.0 0.0 0.06102 + 0.0 0.0 0.06102 END PRINTOUT # NTPR NTPP - 10 0 + 10 0 END QMMM # NTQMMM NTQMSW RCUTQ NTWQMMM QMLJ MMSCAL - 1 4 1.400000 0 0 -1.000000 + 1 4 1.400000 0 0 -1.000000 END STEP # NSTLIM T DT - 100000 0.000000 0.002000 + 100000 0.000000 0.002000 END SYSTEM # NPM NSM - 1 0 + 1 0 END WRITETRAJ # NTWX NTWSE NTWV NTWF NTWE NTWG NTWB - 200 0 0 0 100 0 0 + 200 0 0 0 100 0 0 END diff --git a/examples/example_files/QMMM_files/menthol-methanol-dmf/menthol-methanol-dmf.qmmm b/examples/example_files/QMMM_files/menthol-methanol-dmf/menthol-methanol-dmf.qmmm index d412b53b..5a8f0e6f 100644 --- a/examples/example_files/QMMM_files/menthol-methanol-dmf/menthol-methanol-dmf.qmmm +++ b/examples/example_files/QMMM_files/menthol-methanol-dmf/menthol-methanol-dmf.qmmm @@ -1,9 +1,9 @@ TITLE Custom file header - >>> Generated with PyGromosTools (riniker group) <<< + >>> Generated with PyGromosTools (riniker group) <<< END QMUNIT -# QLGL QEGE QCGC QIGI +# QLGL QEGE QCGC QIGI 0.052918 2625.5 1.0 0.1 END QMZONE diff --git a/examples/example_files/QMMM_files/menthol-methanol-dmf/menthol-methanol-dmf.top b/examples/example_files/QMMM_files/menthol-methanol-dmf/menthol-methanol-dmf.top index 9388278e..f32419e9 100644 --- a/examples/example_files/QMMM_files/menthol-methanol-dmf/menthol-methanol-dmf.top +++ b/examples/example_files/QMMM_files/menthol-methanol-dmf/menthol-methanol-dmf.top @@ -5,7 +5,7 @@ COM_TOP: Combined topology using: 202 .. 261 : /home/fpultar/Documents/calc/mdfptools-test/topo/ERI7-all-atom_54a7.top Parameters from 1, solvent from 1 - >>> Generated with PyGromosTools (riniker group) <<< + >>> Generated with PyGromosTools (riniker group) <<< END PHYSICALCONSTANTS # FPEPSI: 1.0/(4.0*PI*EPS0) (EPS0 is the permittivity of vacuum) @@ -12201,7 +12201,7 @@ PRESSUREGROUPS 1951 END LJEXCEPTIONS -# This block defines special LJ-interactions based on atom numbers +# This block defines special LJ-interactions based on atom numbers # This overrules the normal LJ-parameters (including 1-4 interactions) # NEX: number of exceptions 0 diff --git a/examples/example_files/SD_Simulation/SD_input/6J29.cnf b/examples/example_files/SD_Simulation/SD_input/6J29.cnf index 70942b92..809b8d96 100644 --- a/examples/example_files/SD_Simulation/SD_input/6J29.cnf +++ b/examples/example_files/SD_Simulation/SD_input/6J29.cnf @@ -5,7 +5,7 @@ TITLE >>> line_seperator: '\n' field_seperator: '\t' comments_char: '#' END POSITION -# +# 1 6J29 H9 1 0.317518425 0.323672481 -0.003314757 1 6J29 N1 2 0.227431594 0.278160628 0.000130681 1 6J29 H8 3 0.141678225 0.332229616 0.000171306 diff --git a/examples/example_files/SD_Simulation/SD_input/6J29.imd b/examples/example_files/SD_Simulation/SD_input/6J29.imd index 738e914b..20178027 100644 --- a/examples/example_files/SD_Simulation/SD_input/6J29.imd +++ b/examples/example_files/SD_Simulation/SD_input/6J29.imd @@ -6,69 +6,69 @@ steepest descent energy minimization of the peptide in water END BOUNDCOND # NTB NDFMIN - 0 0 + 0 0 END CONSTRAINT # NTC - 3 + 3 # NTCP NTCP0(1) - 1 0.000100 + 1 0.000100 # NTCS NTCS0(1) - 1 0.000100 + 1 0.000100 END ENERGYMIN # NTEM NCYC DELE DX0 DXM NMIN FLIM - 1 0 0.1 0.01 0.05 2000 0.0 + 1 0 0.1 0.01 0.05 2000 0.0 END FORCE # BONDS ANGLES IMPROPER DIHEDRAL ELECTROSTATIC VDW - 1 1 1 1 1 1 + 1 1 1 1 1 1 # NEGR NRE - 1 27 + 1 27 END INITIALISE # NTIVEL NTISHK NTINHT NTINHB - 0 0 0 0 + 0 0 0 0 # NTISHI NTIRTC NTICOM - 1 0 0 + 1 0 0 # NTISTI - 0 + 0 # IG TEMPI - 210185 300.0 + 210185 300.0 END NONBONDED # NLRELE - 1 + 1 # APPAK RCRF EPSRF NSLFEXCL - 0.0 1.4 61 1 + 0.0 1.4 61 1 # NSHAPE ASHAPE NA2CLC TOLA2 EPSLS - -1 1.4 2 1e-10 0 + -1 1.4 2 1e-10 0 # NKX NKY NKZ KCUT - 10 10 10 100 + 10 10 10 100 # NGX NGY NGZ NASORD NFDORD NALIAS NSPORD - 32 32 32 3 2 3 4 + 32 32 32 3 2 3 4 # NQEVAL FACCUR NRDGRD NWRGRD - 100000 1.6 0 0 + 100000 1.6 0 0 # NLRLJ SLVDNS - 0 33.3 + 0 33.3 END PAIRLIST # ALGORITHM NSNB RCUTP RCUTL SIZE TYPE - 0 5 0.800000 1.400000 0.4 0 + 0 5 0.800000 1.400000 0.4 0 END PRINTOUT # NTPR NTPP - 10 0 + 10 0 END STEP # NSTLIM T DT - 3000 0.000000 0.002000 + 3000 0.000000 0.002000 END SYSTEM # NPM NSM - 1 0 + 1 0 END WRITETRAJ # NTWX NTWSE NTWV NTWF NTWE NTWG NTWB - 100 0 0 0 100 0 0 + 100 0 0 0 100 0 0 END diff --git a/examples/example_files/SD_Simulation/SD_input/6J29.top b/examples/example_files/SD_Simulation/SD_input/6J29.top index 6d405697..888a844a 100644 --- a/examples/example_files/SD_Simulation/SD_input/6J29.top +++ b/examples/example_files/SD_Simulation/SD_input/6J29.top @@ -125,7 +125,7 @@ SOLUTEATOM 21 24 26 4 16 19 22 27 6 1 C7 64 12.011 0.54 1 6 7 8 9 16 18 20 - + 5 10 14 17 21 26 7 1 O1 62 15.9994 -0.557 1 1 8 3 9 16 20 @@ -136,7 +136,7 @@ SOLUTEATOM 19 20 3 13 17 21 10 1 C3 64 12.011 -0.106 1 6 11 12 13 14 16 18 - + 3 15 19 20 11 1 H3 20 1.008 0.128 1 1 12 3 13 14 18 @@ -3313,7 +3313,7 @@ PRESSUREGROUPS 27 END LJEXCEPTIONS -# This block defines special LJ-interactions based on atom numbers +# This block defines special LJ-interactions based on atom numbers # This overrules the normal LJ-parameters (including 1-4 interactions) # NEX: number of exceptions 0 diff --git a/examples/example_files/SD_Simulation/SD_input/6J29_unitedatom_optimised_geometry.pdb b/examples/example_files/SD_Simulation/SD_input/6J29_unitedatom_optimised_geometry.pdb index 4d13769f..1a3cab94 100644 --- a/examples/example_files/SD_Simulation/SD_input/6J29_unitedatom_optimised_geometry.pdb +++ b/examples/example_files/SD_Simulation/SD_input/6J29_unitedatom_optimised_geometry.pdb @@ -1,5 +1,5 @@ HEADER UNCLASSIFIED 05-Jan-21 -TITLE UNITED ATOM STRUCTURE FOR MOLECULE UNL +TITLE UNITED ATOM STRUCTURE FOR MOLECULE UNL AUTHOR GROMOS AUTOMATIC TOPOLOGY BUILDER REVISION 2020-12-16 14:31:35 AUTHOR 2 http://compbio.biosci.uq.edu.au/atb HETATM 1 H9 6J29 0 3.175 3.237 -0.033 1.00 0.00 H diff --git a/examples/example_files/TI_Calculation/TI_input/M030_6KET.disres b/examples/example_files/TI_Calculation/TI_input/M030_6KET.disres index 3fd2f85e..a1766f0c 100644 --- a/examples/example_files/TI_Calculation/TI_input/M030_6KET.disres +++ b/examples/example_files/TI_Calculation/TI_input/M030_6KET.disres @@ -3,9 +3,9 @@ generated disres file with restraintmaker >>> Generated with python lib function_libs utilities. (riniker group) >>> line_seperator: ' \n' field_seperator: ' \t ' END -DISTANCERESSPEC -# KDISH KDISC - 0.1 0.153 +DISTANCERESSPEC +# KDISH KDISC + 0.1 0.153 # i j k l type i j k l type r0 w0 rah ## M03/C6 2 - 6KE/C5 15 2 0 0 0 0 15 0 0 0 0 0.00300 1.00000 1 diff --git a/examples/example_files/TI_Calculation/TI_input/M030_6KET.pdb b/examples/example_files/TI_Calculation/TI_input/M030_6KET.pdb index 71d5adde..cb4db266 100644 --- a/examples/example_files/TI_Calculation/TI_input/M030_6KET.pdb +++ b/examples/example_files/TI_Calculation/TI_input/M030_6KET.pdb @@ -1,29 +1,29 @@ -HETATM 1 C9 M03 0 0 -2.866 0.584 -0.005 1.00 0.00 C -HETATM 2 C6 M03 0 0 -1.384 0.280 0.009 1.00 0.00 C -HETATM 3 C2 M03 0 0 -0.922 -1.041 -0.010 1.00 0.00 C -HETATM 4 H2 M03 0 0 -1.642 -1.858 -0.014 1.00 0.00 H -HETATM 5 C4 M03 0 0 0.449 -1.337 -0.015 1.00 0.00 C -HETATM 6 C7 M03 0 0 0.927 -2.772 0.014 1.00 0.00 C -HETATM 7 C1 M03 0 0 1.362 -0.277 -0.013 1.00 0.00 C -HETATM 8 H1 M03 0 0 2.429 -0.496 -0.026 1.00 0.00 H -HETATM 9 C5 M03 0 0 0.934 1.058 0.002 1.00 0.00 C -HETATM 10 C3 M03 0 0 -0.441 1.318 0.018 1.00 0.00 C -HETATM 11 H3 M03 0 0 -0.788 2.351 0.029 1.00 0.00 H -HETATM 12 C8 M03 0 0 1.941 2.187 -0.002 1.00 0.00 C -HETATM 13 H8 6KE 1 1 -2.881 1.486 0.011 1.00 0.00 H -HETATM 14 O1 6KE 1 1 -2.714 0.528 0.009 1.00 0.00 O -HETATM 15 C5 6KE 1 1 -1.364 0.301 0.005 1.00 0.00 C -HETATM 16 C2 6KE 1 1 -0.937 -1.036 -0.007 1.00 0.00 C -HETATM 17 H2 6KE 1 1 -1.675 -1.832 -0.011 1.00 0.00 H -HETATM 18 C1 6KE 1 1 0.428 -1.304 -0.022 1.00 0.00 C -HETATM 19 H1 6KE 1 1 0.767 -2.337 -0.034 1.00 0.00 H -HETATM 20 C3 6KE 1 1 1.381 -0.278 -0.018 1.00 0.00 C -HETATM 21 H3 6KE 1 1 2.437 -0.522 -0.025 1.00 0.00 H -HETATM 22 C6 6KE 1 1 0.939 1.050 0.002 1.00 0.00 C -HETATM 23 C4 6KE 1 1 -0.435 1.341 0.008 1.00 0.00 C -HETATM 24 H4 6KE 1 1 -0.751 2.381 0.015 1.00 0.00 H -HETATM 25 O2 6KE 1 1 1.763 2.140 0.016 1.00 0.00 O -HETATM 26 C7 6KE 1 1 3.169 1.919 0.106 1.00 0.00 C +HETATM 1 C9 M03 0 0 -2.866 0.584 -0.005 1.00 0.00 C +HETATM 2 C6 M03 0 0 -1.384 0.280 0.009 1.00 0.00 C +HETATM 3 C2 M03 0 0 -0.922 -1.041 -0.010 1.00 0.00 C +HETATM 4 H2 M03 0 0 -1.642 -1.858 -0.014 1.00 0.00 H +HETATM 5 C4 M03 0 0 0.449 -1.337 -0.015 1.00 0.00 C +HETATM 6 C7 M03 0 0 0.927 -2.772 0.014 1.00 0.00 C +HETATM 7 C1 M03 0 0 1.362 -0.277 -0.013 1.00 0.00 C +HETATM 8 H1 M03 0 0 2.429 -0.496 -0.026 1.00 0.00 H +HETATM 9 C5 M03 0 0 0.934 1.058 0.002 1.00 0.00 C +HETATM 10 C3 M03 0 0 -0.441 1.318 0.018 1.00 0.00 C +HETATM 11 H3 M03 0 0 -0.788 2.351 0.029 1.00 0.00 H +HETATM 12 C8 M03 0 0 1.941 2.187 -0.002 1.00 0.00 C +HETATM 13 H8 6KE 1 1 -2.881 1.486 0.011 1.00 0.00 H +HETATM 14 O1 6KE 1 1 -2.714 0.528 0.009 1.00 0.00 O +HETATM 15 C5 6KE 1 1 -1.364 0.301 0.005 1.00 0.00 C +HETATM 16 C2 6KE 1 1 -0.937 -1.036 -0.007 1.00 0.00 C +HETATM 17 H2 6KE 1 1 -1.675 -1.832 -0.011 1.00 0.00 H +HETATM 18 C1 6KE 1 1 0.428 -1.304 -0.022 1.00 0.00 C +HETATM 19 H1 6KE 1 1 0.767 -2.337 -0.034 1.00 0.00 H +HETATM 20 C3 6KE 1 1 1.381 -0.278 -0.018 1.00 0.00 C +HETATM 21 H3 6KE 1 1 2.437 -0.522 -0.025 1.00 0.00 H +HETATM 22 C6 6KE 1 1 0.939 1.050 0.002 1.00 0.00 C +HETATM 23 C4 6KE 1 1 -0.435 1.341 0.008 1.00 0.00 C +HETATM 24 H4 6KE 1 1 -0.751 2.381 0.015 1.00 0.00 H +HETATM 25 O2 6KE 1 1 1.763 2.140 0.016 1.00 0.00 O +HETATM 26 C7 6KE 1 1 3.169 1.919 0.106 1.00 0.00 C CONECT 1 2 CONECT 2 1 3 10 CONECT 3 2 4 5 diff --git a/examples/example_files/TI_Calculation/TI_input/M030_6KET.top b/examples/example_files/TI_Calculation/TI_input/M030_6KET.top index 21aed6c1..9e9310be 100644 --- a/examples/example_files/TI_Calculation/TI_input/M030_6KET.top +++ b/examples/example_files/TI_Calculation/TI_input/M030_6KET.top @@ -118,7 +118,7 @@ SOLUTEATOM 11 2 6 12 3 1 C2 64 12.011 -0.434 1 6 4 5 6 7 9 10 - + 2 8 11 4 1 H2 20 1.008 0.169 1 1 5 3 6 7 10 @@ -146,7 +146,7 @@ SOLUTEATOM 24 2 19 25 16 2 C2 64 12.011 -0.353 1 6 17 18 19 20 22 23 - + 2 21 24 17 2 H2 20 1.008 0.184 1 1 18 3 19 20 23 @@ -3290,7 +3290,7 @@ PRESSUREGROUPS 12 26 END LJEXCEPTIONS -# This block defines special LJ-interactions based on atom numbers +# This block defines special LJ-interactions based on atom numbers # This overrules the normal LJ-parameters (including 1-4 interactions) # NEX: number of exceptions 0 diff --git a/examples/example_files/TI_Calculation/TI_input/vacuum_template.imd b/examples/example_files/TI_Calculation/TI_input/vacuum_template.imd index 232d70c6..13105d8a 100644 --- a/examples/example_files/TI_Calculation/TI_input/vacuum_template.imd +++ b/examples/example_files/TI_Calculation/TI_input/vacuum_template.imd @@ -6,77 +6,77 @@ TITLE END BOUNDCOND # NTB NDFMIN - 0 0 + 0 0 END COMTRANSROT # NSCM - 0 + 0 END CONSTRAINT # NTC - 3 + 3 # NTCP NTCP0(1) - 1 0.0001 + 1 0.0001 # NTCS NTCS0(1) - 1 0.0001 + 1 0.0001 END DISTANCERES # NTDIR NTDIRA CDIR DIR0 TAUDIR FORCESCALE VDIR NTWDIR - 1 0 5000 1 1 0 0 0 + 1 0 5000 1 1 0 0 0 END FORCE # BONDS ANGLES IMPROPER DIHEDRAL ELECTROSTATIC VDW - 0 1 1 1 1 1 + 0 1 1 1 1 1 # NEGR NRE - 9 15 31 48 66 87 108 132 151 170 + 9 15 31 48 66 87 108 132 151 170 END INITIALISE # NTIVEL NTISHK NTINHT NTINHB - 1 3 0 0 + 1 3 0 0 # NTISHI NTIRTC NTICOM - 1 0 0 + 1 0 0 # NTISTI - 1 + 1 # IG TEMPI - 210185 298 + 210185 298 END NONBONDED # NLRELE - 1 + 1 # APPAK RCRF EPSRF NSLFEXCL - 0 1.4 1 1 + 0 1.4 1 1 # NSHAPE ASHAPE NA2CLC TOLA2 EPSLS - 3 1.4 2 1e-10 0 + 3 1.4 2 1e-10 0 # NKX NKY NKZ KCUT - 10 10 10 100 + 10 10 10 100 # NGX NGY NGZ NASORD NFDORD NALIAS NSPORD - 32 32 32 3 2 3 4 + 32 32 32 3 2 3 4 # NQEVAL FACCUR NRDGRD NWRGRD - 100000 1.6 0 0 + 100000 1.6 0 0 # NLRLJ SLVDNS - 0 33.3 + 0 33.3 END PAIRLIST # ALGORITHM NSNB RCUTP RCUTL SIZE TYPE - 0 5 0.8 1.4 0.4 0 + 0 5 0.8 1.4 0.4 0 END PRINTOUT # NTPR NTPP - 5000 0 + 5000 0 END STEP # NSTLIM T DT - 20 0 0.002 + 20 0 0.002 END STOCHDYN # NTSD NTFR NSFR NBREF RCUTF CFRIC TEMPSD - 1 1 100 5 0.3 91.0 298 + 1 1 100 5 0.3 91.0 298 END SYSTEM # NPM NSM - 1 0 + 1 0 END WRITETRAJ # NTWX NTWSE NTWV NTWF NTWE NTWG NTWB - 5000 0 0 0 20 0 0 + 5000 0 0 0 20 0 0 END diff --git a/examples/example_files/TI_Calculation/TI_input/water_template.imd b/examples/example_files/TI_Calculation/TI_input/water_template.imd index 4a9fa2ff..c9c024b4 100644 --- a/examples/example_files/TI_Calculation/TI_input/water_template.imd +++ b/examples/example_files/TI_Calculation/TI_input/water_template.imd @@ -5,41 +5,41 @@ TITLE >>> Generated with python lib function_libs utilities. (riniker group) >>> line_seperator: '\n' field_seperator: '\t' END -BOUNDCOND -# NTB NDFMIN - 1 3 +BOUNDCOND +# NTB NDFMIN + 1 3 END -COMTRANSROT -# NSCM - 1000 +COMTRANSROT +# NSCM + 1000 END -CONSTRAINT -# NTC - 3 -# NTCP NTCP0(1) - 1 0.0001 -# NTCS NTCS0(1) - 1 0.0001 +CONSTRAINT +# NTC + 3 +# NTCP NTCP0(1) + 1 0.0001 +# NTCS NTCS0(1) + 1 0.0001 END -DISTANCERES -# NTDIR NTDIRA CDIR DIR0 TAUDIR FORCESCALE VDIR NTWDIR - 1 0 5000 1 1 0 0 0 +DISTANCERES +# NTDIR NTDIRA CDIR DIR0 TAUDIR FORCESCALE VDIR NTWDIR + 1 0 5000 1 1 0 0 0 END -FORCE -# BONDS ANGLES IMPROPER DIHEDRAL ELECTROSTATIC VDW - 0 1 1 1 1 1 -# NEGR NRE - 10 15 31 48 66 87 108 132 151 170 3095 +FORCE +# BONDS ANGLES IMPROPER DIHEDRAL ELECTROSTATIC VDW + 0 1 1 1 1 1 +# NEGR NRE + 10 15 31 48 66 87 108 132 151 170 3095 END -INITIALISE -# NTIVEL NTISHK NTINHT NTINHB - 0 0 0 0 -# NTISHI NTIRTC NTICOM - 0 0 0 -# NTISTI - 0 -# IG TEMPI - 210185 298 +INITIALISE +# NTIVEL NTISHK NTINHT NTINHB + 0 0 0 0 +# NTISHI NTIRTC NTICOM + 0 0 0 +# NTISTI + 0 +# IG TEMPI + 210185 298 END MULTIBATH # ALGORITHM @@ -55,49 +55,49 @@ MULTIBATH 231 1 1 5332 2 2 END -NONBONDED -# NLRELE - 1 -# APPAK RCRF EPSRF NSLFEXCL - 0 1.4 66.7 1 -# NSHAPE ASHAPE NA2CLC TOLA2 EPSLS - 3 1.4 2 1e-10 0 -# NKX NKY NKZ KCUT - 10 10 10 100 -# NGX NGY NGZ NASORD NFDORD NALIAS NSPORD - 32 32 32 3 2 3 4 -# NQEVAL FACCUR NRDGRD NWRGRD - 100000 1.6 0 0 -# NLRLJ SLVDNS - 0 33.3 +NONBONDED +# NLRELE + 1 +# APPAK RCRF EPSRF NSLFEXCL + 0 1.4 66.7 1 +# NSHAPE ASHAPE NA2CLC TOLA2 EPSLS + 3 1.4 2 1e-10 0 +# NKX NKY NKZ KCUT + 10 10 10 100 +# NGX NGY NGZ NASORD NFDORD NALIAS NSPORD + 32 32 32 3 2 3 4 +# NQEVAL FACCUR NRDGRD NWRGRD + 100000 1.6 0 0 +# NLRLJ SLVDNS + 0 33.3 END -PAIRLIST -# ALGORITHM NSNB RCUTP RCUTL SIZE TYPE - 0 5 0.8 1.4 0.4 0 +PAIRLIST +# ALGORITHM NSNB RCUTP RCUTL SIZE TYPE + 0 5 0.8 1.4 0.4 0 END -PRESSURESCALE -# COUPLE SCALE COMP TAUP VIRIAL - 2 1 0.0004575 0.5 2 -# SEMIANISOTROPIC COUPLINGS(X, Y, Z) - 1 1 1 -# PRES0(1...3,1...3) - 0.06102 0 0 - 0 0.06102 0 - 0 0 0.06102 +PRESSURESCALE +# COUPLE SCALE COMP TAUP VIRIAL + 2 1 0.0004575 0.5 2 +# SEMIANISOTROPIC COUPLINGS(X, Y, Z) + 1 1 1 +# PRES0(1...3,1...3) + 0.06102 0 0 + 0 0.06102 0 + 0 0 0.06102 END -PRINTOUT -# NTPR NTPP - 5000 0 +PRINTOUT +# NTPR NTPP + 5000 0 END -STEP -# NSTLIM T DT - 20 0 0.002 +STEP +# NSTLIM T DT + 20 0 0.002 END -SYSTEM -# NPM NSM - 1 0 +SYSTEM +# NPM NSM + 1 0 +END +WRITETRAJ +# NTWX NTWSE NTWV NTWF NTWE NTWG NTWB + 5000 0 0 0 20 0 0 END -WRITETRAJ -# NTWX NTWSE NTWV NTWF NTWE NTWG NTWB - 5000 0 0 0 20 0 0 -END \ No newline at end of file diff --git a/examples/example_files/off_files/testOFF.cnf b/examples/example_files/off_files/testOFF.cnf index 51c770d0..4249041c 100644 --- a/examples/example_files/off_files/testOFF.cnf +++ b/examples/example_files/off_files/testOFF.cnf @@ -4,7 +4,7 @@ TITLE >>> line_seperator: '\n' field_seperator: '\t' comments_char: '#' END POSITION -# +# 1 C6H12 C 1 0.031454077 -0.138633698 -0.031186310 1 C6H12 C 2 0.146024827 -0.035758228 -0.022023962 1 C6H12 C 3 0.098046543 0.106921880 0.011654682 diff --git a/examples/example_files/off_files/testOFF.imd b/examples/example_files/off_files/testOFF.imd index c1c0eeb9..46bd14bd 100644 --- a/examples/example_files/off_files/testOFF.imd +++ b/examples/example_files/off_files/testOFF.imd @@ -6,81 +6,81 @@ TITLE END AMBER # AMBER AMBSCAL - 1 1.200000 + 1 1.200000 END BOUNDCOND # NTB NDFMIN - 1 3 + 1 3 END COMTRANSROT # NSCM - 1000 + 1000 END CONSTRAINT # NTC - 3 + 3 # NTCP NTCP0(1) - 1 0.000100 + 1 0.000100 # NTCS NTCS0(1) - 1 0.000100 + 1 0.000100 END COVALENTFORM # NTBBH NTBAH NTBDN - 1 1 0 + 1 1 0 END FORCE # BONDS ANGLES IMPROPER DIHEDRAL ELECTROSTATIC VDW - 0 1 1 1 1 1 + 0 1 1 1 1 1 # NEGR NRE - 1 18 + 1 18 END INITIALISE # NTIVEL NTISHK NTINHT NTINHB - 1 1 0 0 + 1 1 0 0 # NTISHI NTIRTC NTICOM - 1 0 1 + 1 0 1 # NTISTI - 1 + 1 # IG TEMPI - 210185 298 + 210185 298 END NONBONDED # NLRELE - 1 + 1 # APPAK RCRF EPSRF NSLFEXCL - 0 1.4 1.0 1 + 0 1.4 1.0 1 # NSHAPE ASHAPE NA2CLC TOLA2 EPSLS - -1 1.4 2 1e-10 0 + -1 1.4 2 1e-10 0 # NKX NKY NKZ KCUT - 10 10 10 100 + 10 10 10 100 # NGX NGY NGZ NASORD NFDORD NALIAS NSPORD - 32 32 32 3 2 3 4 + 32 32 32 3 2 3 4 # NQEVAL FACCUR NRDGRD NWRGRD - 100000 1.6 0 0 + 100000 1.6 0 0 # NLRLJ SLVDNS - 0 33.3 + 0 33.3 END PAIRLIST # ALGORITHM NSNB RCUTP RCUTL SIZE TYPE - 0 5 1.400000 1.400000 0.4 0 + 0 5 1.400000 1.400000 0.4 0 END PRINTOUT # NTPR NTPP - 0 0 + 0 0 END STEP # NSTLIM T DT - 20000 0.000000 0.002000 + 20000 0.000000 0.002000 END STOCHDYN # NTSD NTFR NSFR NBREF RCUTF CFRIC TEMPSD - 1 1 100 5 0.300000 91.000000 298.000000 + 1 1 100 5 0.300000 91.000000 298.000000 END SYSTEM # NPM NSM - 1 0 + 1 0 END WRITETRAJ # NTWX NTWSE NTWV NTWF NTWE NTWG NTWB - 500 0 0 0 500 0 0 + 500 0 0 0 500 0 0 END diff --git a/examples/example_files/off_files/testOFF.top b/examples/example_files/off_files/testOFF.top index 100091cf..a97dee4d 100644 --- a/examples/example_files/off_files/testOFF.top +++ b/examples/example_files/off_files/testOFF.top @@ -297,7 +297,7 @@ PRESSUREGROUPS 18 END LJEXCEPTIONS -# This block defines special LJ-interactions based on atom numbers +# This block defines special LJ-interactions based on atom numbers # This overrules the normal LJ-parameters (including 1-4 interactions) # NEX: number of exceptions 0 diff --git a/examples/example_files/topo_tutorial/test.top b/examples/example_files/topo_tutorial/test.top index a3d0aaa6..a2a6773b 100644 --- a/examples/example_files/topo_tutorial/test.top +++ b/examples/example_files/topo_tutorial/test.top @@ -55,7 +55,7 @@ SOLUTEATOM 18 4 7 8 11 12 6 1 C6 1 12.01078 0.0 1 6 7 8 15 16 17 18 - + 4 9 10 13 14 7 1 H1 2 1.007947 0.0 1 1 8 4 9 10 17 18 @@ -97,7 +97,7 @@ SOLUTEATOM 36 4 25 26 29 30 24 2 C6 1 12.01078 0.0 1 6 25 26 33 34 35 36 - + 4 27 28 31 32 25 2 H1 2 1.007947 0.0 1 1 26 4 27 28 35 36 @@ -139,7 +139,7 @@ SOLUTEATOM 54 4 43 44 47 48 42 3 C6 1 12.01078 0.0 1 6 43 44 51 52 53 54 - + 4 45 46 49 50 43 3 H1 2 1.007947 0.0 1 1 44 4 45 46 53 54 @@ -181,7 +181,7 @@ SOLUTEATOM 72 4 61 62 65 66 60 4 C6 1 12.01078 0.0 1 6 61 62 69 70 71 72 - + 4 63 64 67 68 61 4 H1 2 1.007947 0.0 1 1 62 4 63 64 71 72 @@ -223,7 +223,7 @@ SOLUTEATOM 90 4 79 80 83 84 78 5 C6 1 12.01078 0.0 1 6 79 80 87 88 89 90 - + 4 81 82 85 86 79 5 H1 2 1.007947 0.0 1 1 80 4 81 82 89 90 @@ -265,7 +265,7 @@ SOLUTEATOM 108 4 97 98 101 102 96 6 C6 1 12.01078 0.0 1 6 97 98 105 106 107 108 - + 4 99 100 103 104 97 6 H1 2 1.007947 0.0 1 1 98 4 99 100 107 108 @@ -307,7 +307,7 @@ SOLUTEATOM 126 4 115 116 119 120 114 7 C6 1 12.01078 0.0 1 6 115 116 123 124 125 126 - + 4 117 118 121 122 115 7 H1 2 1.007947 0.0 1 1 116 4 117 118 125 126 @@ -349,7 +349,7 @@ SOLUTEATOM 144 4 133 134 137 138 132 8 C6 1 12.01078 0.0 1 6 133 134 141 142 143 144 - + 4 135 136 139 140 133 8 H1 2 1.007947 0.0 1 1 134 4 135 136 143 144 @@ -391,7 +391,7 @@ SOLUTEATOM 162 4 151 152 155 156 150 9 C6 1 12.01078 0.0 1 6 151 152 159 160 161 162 - + 4 153 154 157 158 151 9 H1 2 1.007947 0.0 1 1 152 4 153 154 161 162 @@ -433,7 +433,7 @@ SOLUTEATOM 180 4 169 170 173 174 168 10 C6 1 12.01078 0.0 1 6 169 170 177 178 179 180 - + 4 171 172 175 176 169 10 H1 2 1.007947 0.0 1 1 170 4 171 172 179 180 @@ -463,7 +463,7 @@ SOLUTEATOM 189 6 184 190 192 193 194 195 182 11 C2 3 12.01078 0 1 6 183 184 186 188 189 190 - + 3 185 187 191 183 11 C3 3 12.01078 0 1 5 184 185 189 190 191 3 186 188 192 @@ -472,7 +472,7 @@ SOLUTEATOM 185 11 C5 3 12.01078 0 1 4 186 187 191 192 5 188 190 193 194 195 186 11 C6 3 12.01078 0 1 6 187 188 192 193 194 195 - + 2 189 191 187 11 C7 1 12.01078 0 1 3 193 194 195 2 188 192 diff --git a/examples/example_gromos_files.ipynb b/examples/example_gromos_files.ipynb index fae0337e..36b13eb4 100644 --- a/examples/example_gromos_files.ipynb +++ b/examples/example_gromos_files.ipynb @@ -1480,4 +1480,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} \ No newline at end of file +} diff --git a/examples/example_topology_creation.ipynb b/examples/example_topology_creation.ipynb index 8c7dcb28..61e1b7fd 100644 --- a/examples/example_topology_creation.ipynb +++ b/examples/example_topology_creation.ipynb @@ -981,4 +981,4 @@ "source": [] } ] -} \ No newline at end of file +} diff --git a/pygromos/__init__.py b/pygromos/__init__.py index 21ba7d8c..ed00d610 100644 --- a/pygromos/__init__.py +++ b/pygromos/__init__.py @@ -8,7 +8,8 @@ # Handle versioneer from ._version import get_versions + versions = get_versions() -__version__ = versions['version'] -__git_revision__ = versions['full-revisionid'] +__version__ = versions["version"] +__git_revision__ = versions["full-revisionid"] del get_versions, versions diff --git a/pygromos/_version.py b/pygromos/_version.py index 36ab4963..71656261 100644 --- a/pygromos/_version.py +++ b/pygromos/_version.py @@ -1,4 +1,3 @@ - # This file helps to compute a version number in source trees obtained from # git-archive tarball (such as those provided by githubs download-from-tag # feature). Distribution tarballs (built by setup.py sdist) and build @@ -58,17 +57,18 @@ class NotThisMethod(Exception): def register_vcs_handler(vcs, method): # decorator """Decorator to mark a method as the handler for a particular VCS.""" + def decorate(f): """Store f in HANDLERS[vcs][method].""" if vcs not in HANDLERS: HANDLERS[vcs] = {} HANDLERS[vcs][method] = f return f + return decorate -def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, - env=None): +def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, env=None): """Call the given command(s).""" assert isinstance(commands, list) p = None @@ -76,10 +76,9 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, try: dispcmd = str([c] + args) # remember shell=False, so use git.cmd on windows, not just git - p = subprocess.Popen([c] + args, cwd=cwd, env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr - else None)) + p = subprocess.Popen( + [c] + args, cwd=cwd, env=env, stdout=subprocess.PIPE, stderr=(subprocess.PIPE if hide_stderr else None) + ) break except EnvironmentError: e = sys.exc_info()[1] @@ -116,16 +115,19 @@ def versions_from_parentdir(parentdir_prefix, root, verbose): for _ in range(3): dirname = os.path.basename(root) if dirname.startswith(parentdir_prefix): - return {"version": dirname[len(parentdir_prefix):], - "full-revisionid": None, - "dirty": False, "error": None, "date": None} + return { + "version": dirname[len(parentdir_prefix) :], + "full-revisionid": None, + "dirty": False, + "error": None, + "date": None, + } else: rootdirs.append(root) root = os.path.dirname(root) # up a level if verbose: - print("Tried directories %s but none started with prefix %s" % - (str(rootdirs), parentdir_prefix)) + print("Tried directories %s but none started with prefix %s" % (str(rootdirs), parentdir_prefix)) raise NotThisMethod("rootdir doesn't start with parentdir_prefix") @@ -181,7 +183,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of # just "foo-1.0". If we see a "tag: " prefix, prefer those. TAG = "tag: " - tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) + tags = set([r[len(TAG) :] for r in refs if r.startswith(TAG)]) if not tags: # Either we're using git < 1.8.3, or there really are no tags. We use # a heuristic: assume all version tags have a digit. The old git %d @@ -190,7 +192,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # between branches and tags. By ignoring refnames without digits, we # filter out many common branch names like "release" and # "stabilization", as well as "HEAD" and "master". - tags = set([r for r in refs if re.search(r'\d', r)]) + tags = set([r for r in refs if re.search(r"\d", r)]) if verbose: print("discarding '%s', no digits" % ",".join(refs - tags)) if verbose: @@ -198,19 +200,26 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): for ref in sorted(tags): # sorting will prefer e.g. "2.0" over "2.0rc1" if ref.startswith(tag_prefix): - r = ref[len(tag_prefix):] + r = ref[len(tag_prefix) :] if verbose: print("picking %s" % r) - return {"version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": None, - "date": date} + return { + "version": r, + "full-revisionid": keywords["full"].strip(), + "dirty": False, + "error": None, + "date": date, + } # no suitable tags, so version is "0+unknown", but full hex is still there if verbose: print("no suitable tags, using unknown + full revision id") - return {"version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": "no suitable tags", "date": None} + return { + "version": "0+unknown", + "full-revisionid": keywords["full"].strip(), + "dirty": False, + "error": "no suitable tags", + "date": None, + } @register_vcs_handler("git", "pieces_from_vcs") @@ -225,8 +234,7 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] - out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, - hide_stderr=True) + out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True) if rc != 0: if verbose: print("Directory %s not under git control" % root) @@ -234,10 +242,9 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", - "--always", "--long", - "--match", "%s*" % tag_prefix], - cwd=root) + describe_out, rc = run_command( + GITS, ["describe", "--tags", "--dirty", "--always", "--long", "--match", "%s*" % tag_prefix], cwd=root + ) # --long was added in git-1.5.5 if describe_out is None: raise NotThisMethod("'git describe' failed") @@ -260,17 +267,16 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): dirty = git_describe.endswith("-dirty") pieces["dirty"] = dirty if dirty: - git_describe = git_describe[:git_describe.rindex("-dirty")] + git_describe = git_describe[: git_describe.rindex("-dirty")] # now we have TAG-NUM-gHEX or HEX if "-" in git_describe: # TAG-NUM-gHEX - mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) + mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe) if not mo: # unparseable. Maybe git-describe is misbehaving? - pieces["error"] = ("unable to parse git-describe output: '%s'" - % describe_out) + pieces["error"] = "unable to parse git-describe output: '%s'" % describe_out return pieces # tag @@ -279,10 +285,9 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if verbose: fmt = "tag '%s' doesn't start with prefix '%s'" print(fmt % (full_tag, tag_prefix)) - pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" - % (full_tag, tag_prefix)) + pieces["error"] = "tag '%s' doesn't start with prefix '%s'" % (full_tag, tag_prefix) return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix):] + pieces["closest-tag"] = full_tag[len(tag_prefix) :] # distance: number of commits since tag pieces["distance"] = int(mo.group(2)) @@ -293,13 +298,11 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): else: # HEX: no tags pieces["closest-tag"] = None - count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], - cwd=root) + count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], cwd=root) pieces["distance"] = int(count_out) # total number of commits # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], - cwd=root)[0].strip() + date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[0].strip() pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) return pieces @@ -330,8 +333,7 @@ def render_pep440(pieces): rendered += ".dirty" else: # exception #1 - rendered = "0+untagged.%d.g%s" % (pieces["distance"], - pieces["short"]) + rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered @@ -445,11 +447,13 @@ def render_git_describe_long(pieces): def render(pieces, style): """Render the given version pieces into the requested style.""" if pieces["error"]: - return {"version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None} + return { + "version": "unknown", + "full-revisionid": pieces.get("long"), + "dirty": None, + "error": pieces["error"], + "date": None, + } if not style or style == "default": style = "pep440" # the default @@ -469,9 +473,13 @@ def render(pieces, style): else: raise ValueError("unknown style '%s'" % style) - return {"version": rendered, "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], "error": None, - "date": pieces.get("date")} + return { + "version": rendered, + "full-revisionid": pieces["long"], + "dirty": pieces["dirty"], + "error": None, + "date": pieces.get("date"), + } def get_versions(): @@ -485,8 +493,7 @@ def get_versions(): verbose = cfg.verbose try: - return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, - verbose) + return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, verbose) except NotThisMethod: pass @@ -495,13 +502,16 @@ def get_versions(): # versionfile_source is the relative path from the top of the source # tree (where the .git directory might live) to this file. Invert # this to find the root from __file__. - for i in cfg.versionfile_source.split('/'): + for i in cfg.versionfile_source.split("/"): root = os.path.dirname(root) except NameError: - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, - "error": "unable to find root of source tree", - "date": None} + return { + "version": "0+unknown", + "full-revisionid": None, + "dirty": None, + "error": "unable to find root of source tree", + "date": None, + } try: pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) @@ -515,6 +525,10 @@ def get_versions(): except NotThisMethod: pass - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, - "error": "unable to compute version", "date": None} + return { + "version": "0+unknown", + "full-revisionid": None, + "dirty": None, + "error": "unable to compute version", + "date": None, + } diff --git a/pygromos/analysis/__init__.py b/pygromos/analysis/__init__.py index 5b669adc..7f911660 100644 --- a/pygromos/analysis/__init__.py +++ b/pygromos/analysis/__init__.py @@ -1,3 +1,3 @@ """ This is a future folder -""" \ No newline at end of file +""" diff --git a/pygromos/analysis/coordinate_analysis.py b/pygromos/analysis/coordinate_analysis.py index 98b46c7e..124650d9 100644 --- a/pygromos/analysis/coordinate_analysis.py +++ b/pygromos/analysis/coordinate_analysis.py @@ -1,10 +1,12 @@ import numpy as np -def calculate_distance(atomA:np.array, atomB:np.array)->np.array: + +def calculate_distance(atomA: np.array, atomB: np.array) -> np.array: return np.sqrt(np.sum((atomB - atomA) ** 2)) -def rms(in_values)->float: + +def rms(in_values) -> float: """helper function for RMSD. Calculates the root mean square for a array of (position/velocity) arrays Parameters @@ -16,9 +18,10 @@ def rms(in_values)->float: float root mean square """ - return np.sqrt(np.sum(np.square(in_values))/len(in_values)) + return np.sqrt(np.sum(np.square(in_values)) / len(in_values)) -def periodic_distance(vec:np.array, grid:np.array) -> np.array: + +def periodic_distance(vec: np.array, grid: np.array) -> np.array: for i in range(3): if vec[i] > (grid[i] / 2): @@ -28,8 +31,8 @@ def periodic_distance(vec:np.array, grid:np.array) -> np.array: return vec -def periodic_shift(vec:np.array, grid:np.array) -> np.array: +def periodic_shift(vec: np.array, grid: np.array) -> np.array: for i in range(3): - if vec[i] > (grid[i]/2): - vec[i] = vec[i]-grid[i] + if vec[i] > (grid[i] / 2): + vec[i] = vec[i] - grid[i] return vec diff --git a/pygromos/analysis/energy_analysis.py b/pygromos/analysis/energy_analysis.py index caf94e49..701d9609 100644 --- a/pygromos/analysis/energy_analysis.py +++ b/pygromos/analysis/energy_analysis.py @@ -3,7 +3,7 @@ from scipy import constants -def get_density(mass:np.array, volume:np.array, atomu=1/constants.Avogadro*10e23)->np.array: +def get_density(mass: np.array, volume: np.array, atomu=1 / constants.Avogadro * 10e23) -> np.array: """ Calculate the density @@ -20,9 +20,10 @@ def get_density(mass:np.array, volume:np.array, atomu=1/constants.Avogadro*10e23 return atomu * mass / volume -def get_Hvap(liq_totpot_energy:float, gas_totpot_energy:float, - nMolecules=1, temperature=None, R=constants.R/1000) -> float: +def get_Hvap( + liq_totpot_energy: float, gas_totpot_energy: float, nMolecules=1, temperature=None, R=constants.R / 1000 +) -> float: # calculate heat of vaporization - rt_constant = R * temperature # R in kilojoule_per_mole/kelvin * T + rt_constant = R * temperature # R in kilojoule_per_mole/kelvin * T heat_vap = gas_totpot_energy - liq_totpot_energy / nMolecules + rt_constant - return heat_vap \ No newline at end of file + return heat_vap diff --git a/pygromos/analysis/error_estimate.py b/pygromos/analysis/error_estimate.py index d11b8b4f..4d47653a 100644 --- a/pygromos/analysis/error_estimate.py +++ b/pygromos/analysis/error_estimate.py @@ -11,18 +11,20 @@ from typing import List import numpy as np + class error_estimator: - ''' + """ Class to calculate the Error Estimate as implemented in ene_ana - ''' - def __init__(self,values:List[float]): - ''' + """ + + def __init__(self, values: List[float]): + """ Initialize calculation Parameters ---------- values : List[float] list of ordered values for which the error should be estimated - ''' + """ # Prepare blocks self.values = values self.blksz = 50 @@ -31,38 +33,38 @@ def __init__(self,values:List[float]): self.d_blocksize = [] def calculate_rmsd(self): - ''' + """ Calculate rmsd Returns ------- rmsd : float rmsd of values - ''' + """ sum = 0 ssum = 0 for v in self.values: sum += v - ssum += v*v + ssum += v * v sum /= len(self.values) ssum /= len(self.values) - msd = ssum - sum*sum + msd = ssum - sum * sum return np.sqrt(msd) def calculate_error_estimate(self): - ''' + """ Calculation of the Error Estimate as in ene_ana Returns ------- d_ee : float Error Estimate for provided list - ''' + """ # Setup Blocks - while(4*self.blksz < self.d_counter): + while 4 * self.blksz < self.d_counter: self.d_blocksize.append(int(self.blksz)) self.old = int(self.blksz) - while(self.old==int(self.blksz)): - self.blksz = self.blksz*1.07177 + while self.old == int(self.blksz): + self.blksz = self.blksz * 1.07177 # Set start Variables Nblocks = len(self.d_blocksize) @@ -75,14 +77,14 @@ def calculate_error_estimate(self): x = np.zeros(Nblocks) for j in range(Nblocks): - Nblcki= self.d_counter // self.d_blocksize[j] + Nblcki = self.d_counter // self.d_blocksize[j] - rmsd2=0 + rmsd2 = 0 for i in range(Nblcki): start = i * self.d_blocksize[j] - end = (i+1) * self.d_blocksize[j] + end = (i + 1) * self.d_blocksize[j] ave = np.mean(self.values[start:end]) - rmsd2 += (ave-runave) * (ave-runave) + rmsd2 += (ave - runave) * (ave - runave) rmsd2 = rmsd2 / Nblcki @@ -95,12 +97,12 @@ def calculate_error_estimate(self): for i in range(Nblocks): sx += x[i] sf += fit[i] - sfx += x[i]*fit[i] - sxx += x[i]*x[i] + sfx += x[i] * fit[i] + sxx += x[i] * x[i] - a = (sf*sx/Nblocks-sfx)/(sx*sx/Nblocks - sxx) - b = (sf - a*sx)/Nblocks + a = (sf * sx / Nblocks - sfx) / (sx * sx / Nblocks - sxx) + b = (sf - a * sx) / Nblocks - d_ee = np.sqrt(b/self.d_counter)*runrmsd + d_ee = np.sqrt(b / self.d_counter) * runrmsd - return d_ee \ No newline at end of file + return d_ee diff --git a/pygromos/analysis/free_energy_calculation.py b/pygromos/analysis/free_energy_calculation.py index 80338d7a..dc272d72 100644 --- a/pygromos/analysis/free_energy_calculation.py +++ b/pygromos/analysis/free_energy_calculation.py @@ -35,8 +35,11 @@ def __str__(self): msg = "" msg += self.__class__.__name__ + "\n" msg += "\tEquation: " + str(self.equation) + "\n" - msg += "\tConstants:\n\t\t" + "\n\t\t".join( - [str(key) + ":\t" + str(value) for key, value in self.constants.items()]) + "\n" + msg += ( + "\tConstants:\n\t\t" + + "\n\t\t".join([str(key) + ":\t" + str(value) for key, value in self.constants.items()]) + + "\n" + ) msg += "\tsimplified Equation: " + str(self.simplified_equation) + "\n" return msg @@ -48,7 +51,7 @@ def _update_function(self): @classmethod def _prepare_type(self, *arrays): - return tuple(map(lambda arr: np.array(list(map(lambda x: np.float(x), arr)),ndmin=1), arrays)) + return tuple(map(lambda arr: np.array(list(map(lambda x: np.float(x), arr)), ndmin=1), arrays)) @classmethod def get_equation(cls) -> sp.Function: @@ -73,15 +76,22 @@ def set_parameters(self): class zwanzigEquation(_FreeEnergyCalculator): """Zwanzig Equation - This class is a nice wrapper for the zwanzig Equation. - dF = - \beta \ln(\langle e^(-beta(V_j-V_i)) \rangle) + This class is a nice wrapper for the zwanzig Equation. + dF = - \beta \ln(\langle e^(-beta(V_j-V_i)) \rangle) """ + k, T, Vi, Vj = sp.symbols("k T, Vi, Vj") equation: sp.Function = -(1 / (k * T)) * sp.log(sp.exp(-(1 / (k * T)) * (Vj - Vi))) constants: dict - def __init__(self, T: float = 298, k: float = const.k * const.Avogadro, kT: bool = False, kJ: bool = False, - kCal: bool = False): + def __init__( + self, + T: float = 298, + k: float = const.k * const.Avogadro, + kT: bool = False, + kJ: bool = False, + kCal: bool = False, + ): """ __init__ Here you can set Class wide the parameters T and k for the Zwanzig Equation @@ -100,11 +110,11 @@ def __init__(self, T: float = 298, k: float = const.k * const.Avogadro, kT: bool """ self.constants = {} - if (kT): + if kT: self.set_parameters(T=1, k=1) - elif (kJ): + elif kJ: self.set_parameters(T=T, k=const.k * const.Avogadro / 1000) - elif (kCal): + elif kCal: self.set_parameters(T=T, k=const.k * const.Avogadro * self.J_to_cal / 1000) else: self.set_parameters(T=T, k=k) @@ -154,10 +164,12 @@ def _calculate_implementation_bruteForce(self, Vi: (Iterable, Number), Vj: (Iter free energy difference """ - if (not (len(Vi) == len(Vj))): + if not (len(Vi) == len(Vj)): raise ValueError( - "Zwanzig Error: The given arrays for Vi and Vj must have the same length. \n Actually they have: " + str( - len(Vi) + " \t " + str(len(Vj))) + "\n") + "Zwanzig Error: The given arrays for Vi and Vj must have the same length. \n Actually they have: " + + str(len(Vi) + " \t " + str(len(Vj))) + + "\n" + ) # Typcasting Vi, Vj = self._prepare_type(Vi, Vj) @@ -165,14 +177,15 @@ def _calculate_implementation_bruteForce(self, Vi: (Iterable, Number), Vj: (Iter beta = 1 / (self.constants[self.k] * self.constants[self.T]) # calculate Beta # Calculate the potential energy difference in reduced units of kT - dVij = - beta * (Vj - Vi) + dVij = -beta * (Vj - Vi) # Exponentiate to obtain exp(-Delta U/kT) try: edVij = self.exp(dVij) except OverflowError: raise OverflowError( - "Zwanzig Error: Overflow in exponentiation of potential energy difference. Aborting calculation.") + "Zwanzig Error: Overflow in exponentiation of potential energy difference. Aborting calculation." + ) # average of exponents meandVij = np.mean(edVij) @@ -180,10 +193,11 @@ def _calculate_implementation_bruteForce(self, Vi: (Iterable, Number), Vj: (Iter # Return free energy difference try: # dF = zwanzigEquation.calculate(Vi, Vr) - zwanzigEquation.calculate(Vj, Vr) - dF = - (1 / beta) * (meandVij).ln() + dF = -(1 / beta) * (meandVij).ln() except ValueError: raise ValueError( - "Zwanzig Error: Problems taking logarithm of the average exponentiated potential energy difference ") + "Zwanzig Error: Problems taking logarithm of the average exponentiated potential energy difference " + ) return dF @@ -213,16 +227,18 @@ def _calculate_meanEfficient(self, Vi: (Iterable, Number), Vj: (Iterable, Number float free energy difference """ - if (not (len(Vi) == len(Vj))): + if not (len(Vi) == len(Vj)): raise ValueError( - "Zwanzig Error: The given arrays for Vi and Vj must have the same length. \n Actually they have: " + str( - len(Vi) + " \t " + str(len(Vj))) + "\n") + "Zwanzig Error: The given arrays for Vi and Vj must have the same length. \n Actually they have: " + + str(len(Vi) + " \t " + str(len(Vj))) + + "\n" + ) Vi, Vj = self._prepare_type(Vi, Vj) beta = 1 / (self.constants[self.k] * self.constants[self.T]) # Calculate the potential energy difference in reduced units of kT - dVij = - beta * ( Vj - Vi) + dVij = -beta * (Vj - Vi) # Calculate offset for increased numerical stability meandVij = np.mean(dVij) @@ -232,15 +248,17 @@ def _calculate_meanEfficient(self, Vi: (Iterable, Number), Vj: (Iterable, Number edVij = self.exp(dVij - meandVij) except OverflowError: raise OverflowError( - "Zwanzig Error: Overflow in exponentiation of potential energy difference. Aborting calculation.") + "Zwanzig Error: Overflow in exponentiation of potential energy difference. Aborting calculation." + ) # Return free energy difference try: - dF = - (1 / beta) * ((np.mean(edVij)).ln() + meandVij) + dF = -(1 / beta) * ((np.mean(edVij)).ln() + meandVij) except ValueError: raise ValueError( - "Zwanzig Error: Problems taking logarithm of the average exponentiated potential energy difference " + str( - np.mean(edVij))) + "Zwanzig Error: Problems taking logarithm of the average exponentiated potential energy difference " + + str(np.mean(edVij)) + ) return dF @@ -269,23 +287,26 @@ def _calculate_efficient(self, Vi: (Iterable, Number), Vj: (Iterable, Number)) - float free energy difference """ - if (not (len(Vi) == len(Vj))): + if not (len(Vi) == len(Vj)): raise ValueError( - "Zwanzig Error: The given arrays for Vi and Vj must have the same length. \n Actually they have: " + str( - len(Vi) + " \t " + str(len(Vj))) + "\n") + "Zwanzig Error: The given arrays for Vi and Vj must have the same length. \n Actually they have: " + + str(len(Vi) + " \t " + str(len(Vj))) + + "\n" + ) Vi, Vj = self._prepare_type(Vi, Vj) beta = 1 / (self.constants[self.k] * self.constants[self.T]) # Calculate the potential energy difference in reduced units of kT - dVij = - beta * (Vj - Vi) + dVij = -beta * (Vj - Vi) # Return free energy difference from scipy import special as s - dF = - np.float(1 / beta) * s.logsumexp(np.array(dVij, dtype=np.float), b=1 / len(dVij)) + + dF = -np.float(1 / beta) * s.logsumexp(np.array(dVij, dtype=np.float), b=1 / len(dVij)) return dF - def _calculate_mpmath(self, Vi: (Iterable, Number), Vj: (Iterable, Number))->float: + def _calculate_mpmath(self, Vi: (Iterable, Number), Vj: (Iterable, Number)) -> float: """ implementation of zwanzig with mpmath package, another way of having a robust variant, but this one is very close to the initial equation thanks to the mpmath package. @@ -303,7 +324,9 @@ def _calculate_mpmath(self, Vi: (Iterable, Number), Vj: (Iterable, Number))->fl """ beta = np.float(1 / (self.constants[self.k] * self.constants[self.T])) - return - (1 / beta) * np.float(mp.ln(np.mean(list(map(mp.exp, -beta*(np.array(Vj, ndmin=1) - np.array(Vi, ndmin=1))))))) + return -(1 / beta) * np.float( + mp.ln(np.mean(list(map(mp.exp, -beta * (np.array(Vj, ndmin=1) - np.array(Vi, ndmin=1)))))) + ) def set_parameters(self, T: float = None, k: float = None): """ @@ -316,10 +339,10 @@ def set_parameters(self, T: float = None, k: float = None): boltzmann Constant, defaults to const.k*const.Avogadro """ - if (isinstance(T, (Number))): + if isinstance(T, (Number)): self.constants.update({self.T: T}) - if (isinstance(k, (Number))): + if isinstance(k, (Number)): self.constants.update({self.k: k}) self._update_function() @@ -330,16 +353,24 @@ class zwanzig(zwanzigEquation): class threeStateZwanzig(zwanzigEquation): """ - this class provides the implementation for the Free energy calculation with EDS. - It calculates the free energy via the reference state. - $dF = dF_{BR}-dF_{AR} = \frac{1}{\beta} * ( \ln(\langle e^{-\beta * (V_j-V_R)}\rangle) - \ln(\langle e^{-\beta * (V_i-V_R)}\rangle))$ + this class provides the implementation for the Free energy calculation with EDS. + It calculates the free energy via the reference state. + $dF = dF_{BR}-dF_{AR} = \frac{1}{\beta} * ( \ln(\langle e^{-\beta * (V_j-V_R)}\rangle) - \ln(\langle e^{-\beta * (V_i-V_R)}\rangle))$ """ + k, T, Vi, Vj, Vr = sp.symbols("k T Vi Vj Vr") equation: sp.Function = -(1 / (k * T)) * ( - sp.log(sp.exp(-(1 / (k * T)) * (Vi - Vr))) - sp.log(sp.exp(-(1 / (k * T)) * (Vj - Vr)))) - - def __init__(self, kCal: bool = False, T: float = 298, k: float = const.k * const.Avogadro, kT: bool = False, - kJ: bool = False): + sp.log(sp.exp(-(1 / (k * T)) * (Vi - Vr))) - sp.log(sp.exp(-(1 / (k * T)) * (Vj - Vr))) + ) + + def __init__( + self, + kCal: bool = False, + T: float = 298, + k: float = const.k * const.Avogadro, + kT: bool = False, + kJ: bool = False, + ): """ __init__ this class provides the implementation for the Free energy calculation with EDS. @@ -359,8 +390,9 @@ def __init__(self, kCal: bool = False, T: float = 298, k: float = const.k * cons """ super().__init__(kCal=kCal, T=T, k=k, kT=kT, kJ=kJ) - def calculate(self, Vi: (Iterable[Number], Number), Vj: (Iterable[Number], Number), - Vr: (Iterable[Number], Number)) -> float: + def calculate( + self, Vi: (Iterable[Number], Number), Vj: (Iterable[Number], Number), Vr: (Iterable[Number], Number) + ) -> float: """ calculate this method calculates the zwanzig equation via the intermediate reference state R using the Zwanzig equation. @@ -379,8 +411,9 @@ def calculate(self, Vi: (Iterable[Number], Number), Vj: (Iterable[Number], Numbe """ return float(self._calculate_implementation_useZwanzig(Vi=Vi, Vj=Vj, Vr=Vr)) - def _calculate_implementation_useZwanzig(self, Vi: (Iterable, Number), Vj: (Iterable, Number), - Vr: (Iterable[Number], Number)) -> float: + def _calculate_implementation_useZwanzig( + self, Vi: (Iterable, Number), Vj: (Iterable, Number), Vr: (Iterable[Number], Number) + ) -> float: """ calculate this method calculates the zwanzig equation via the intermediate reference state R using the Zwanzig equation. @@ -398,10 +431,12 @@ def _calculate_implementation_useZwanzig(self, Vi: (Iterable, Number), Vj: (Iter float free energy difference """ - if (not (len(Vi) == len(Vj) == len(Vr))): + if not (len(Vi) == len(Vj) == len(Vr)): raise ValueError( - "Zwanzig Error: The given arrays for Vi and Vj must have the same length. \n Actually they have: " + str( - len(Vi) + " \t " + str(len(Vj))) + "\n") + "Zwanzig Error: The given arrays for Vi and Vj must have the same length. \n Actually they have: " + + str(len(Vi) + " \t " + str(len(Vj))) + + "\n" + ) # Type Casting Vi, Vj, Vr = self._prepare_type(Vi, Vj, Vr) @@ -432,9 +467,11 @@ class bennetAcceptanceRatio(_FreeEnergyCalculator): with : $ f(x) = \frac{1}{1+e^(\beta x)}$ - fermi function """ + k, T, beta, C, Vi_i, Vj_i, Vi_j, Vj_j = sp.symbols("k T beta C Vi_i Vj_i Vi_j Vj_j") equation: sp.Function = (1 / (k * T)) * ( - sp.log(sp.exp((1 / (k * T)) * (Vi_j - Vj_j + C))) - sp.log(sp.exp((1 / (k * T)) * (Vj_i - Vi_i + C)))) + sp.log(sp.exp((1 / (k * T)) * (Vi_j - Vj_j + C))) - sp.log(sp.exp((1 / (k * T)) * (Vj_i - Vi_i + C))) + ) constants: dict = {T: 298, k: const.k * const.Avogadro, C: Number} # Numeric parameters @@ -442,9 +479,18 @@ class bennetAcceptanceRatio(_FreeEnergyCalculator): max_iterations: int min_iterations: int - def __init__(self, C: float = 0.0, T: float = 298, k: float = const.k * const.Avogadro, - kT: bool = False, kJ: bool = False, kCal: bool = False, - convergence_radius: float = 10 ** (-5), max_iterations: int = 500, min_iterations: int = 1): + def __init__( + self, + C: float = 0.0, + T: float = 298, + k: float = const.k * const.Avogadro, + kT: bool = False, + kJ: bool = False, + kCal: bool = False, + convergence_radius: float = 10 ** (-5), + max_iterations: int = 500, + min_iterations: int = 1, + ): """ __init__ Here you can set Class wide the parameters T and k for the bennet acceptance ration (BAR) Equation @@ -471,11 +517,11 @@ def __init__(self, C: float = 0.0, T: float = 298, k: float = const.k * const.Av """ self.constants = {} - if (kT): + if kT: self.set_parameters(T=1, k=1, C=C) - elif (kJ): + elif kJ: self.set_parameters(T=T, k=const.k * const.Avogadro / 1000, C=C) - elif (kCal): + elif kCal: self.set_parameters(T=T, k=const.k * const.Avogadro * self.J_to_cal / 1000, C=C) else: self.set_parameters(T=T, k=k) @@ -487,8 +533,14 @@ def __init__(self, C: float = 0.0, T: float = 298, k: float = const.k * const.Av self._update_function() - def calculate(self, Vi_i: Iterable[Number], Vj_i: Iterable[Number], - Vi_j: Iterable[Number], Vj_j: Iterable[Number], verbose: bool = False) -> float: + def calculate( + self, + Vi_i: Iterable[Number], + Vj_i: Iterable[Number], + Vi_j: Iterable[Number], + Vj_j: Iterable[Number], + verbose: bool = False, + ) -> float: """ calculate this function is calculating the free energy difference of two states with the BAR method. @@ -530,8 +582,8 @@ def _calc_bar(self, C: Number, Vj_i: np.array, Vi_i: np.array, Vi_j: np.array, V free energy difference """ # Calculate the potential energy difference in reduced units of kT - dV_j = ((Vi_j - Vj_j) + C) - dV_i = ((Vj_i - Vi_i) - C) + dV_j = (Vi_j - Vj_j) + C + dV_i = (Vj_i - Vi_i) - C # Exponentiate to obtain fermi(-Delta U/kT) try: @@ -539,7 +591,8 @@ def _calc_bar(self, C: Number, Vj_i: np.array, Vi_i: np.array, Vi_j: np.array, V ferm_dV_j = 1 / (1 + self.exp(self.constants[self.beta] * dV_j)) except OverflowError: raise OverflowError( - "Zwanzig Error: Overflow in exponentiation of potential energy difference. Aborting calculation.") + "Zwanzig Error: Overflow in exponentiation of potential energy difference. Aborting calculation." + ) # get average mean_edV_i = np.mean(ferm_dV_i) @@ -550,8 +603,9 @@ def _calc_bar(self, C: Number, Vj_i: np.array, Vi_i: np.array, Vi_j: np.array, V ddF = (1 / self.constants[self.beta]) * self.ln(mean_edV_j / mean_edV_i) except ValueError as err: raise ValueError( - "BAR Error: Problems taking logarithm of the average exponentiated potential energy difference " + str( - err.args)) + "BAR Error: Problems taking logarithm of the average exponentiated potential energy difference " + + str(err.args) + ) dF = ddF + C return dF @@ -583,11 +637,12 @@ def _calc_bar_mpmath(self, C: Number, Vj_i: np.array, Vi_i: np.array, Vi_j: np.a # Exponentiate to obtain fermi(-Delta U/kT) try: - ferm_dV_j = self.fermifunc(dV_j,self.constants[self.beta]) - ferm_dV_i = self.fermifunc(dV_i,self.constants[self.beta]) + ferm_dV_j = self.fermifunc(dV_j, self.constants[self.beta]) + ferm_dV_i = self.fermifunc(dV_i, self.constants[self.beta]) except OverflowError: raise OverflowError( - "Zwanzig Error: Overflow in exponentiation of potential energy difference. Aborting calculation.") + "Zwanzig Error: Overflow in exponentiation of potential energy difference. Aborting calculation." + ) # get average mean_edV_j = np.mean(ferm_dV_j) @@ -598,15 +653,21 @@ def _calc_bar_mpmath(self, C: Number, Vj_i: np.array, Vi_i: np.array, Vi_j: np.a ddF = (1 / self.constants[self.beta]) * mp.ln(mean_edV_j / mean_edV_i) except ValueError as err: raise ValueError( - "BAR Error: Problems taking logarithm of the average exponentiated potential energy difference " + str( - err.args)) + "BAR Error: Problems taking logarithm of the average exponentiated potential energy difference " + + str(err.args) + ) return np.float(ddF + C) - - def _calculate_optimize(self, Vi_i: (Iterable[Number], Number), Vj_i: (Iterable[Number], Number), - Vi_j: (Iterable[Number], Number), Vj_j: (Iterable[Number], Number), C0: float = 0, - verbose: bool = False) -> float: + def _calculate_optimize( + self, + Vi_i: (Iterable[Number], Number), + Vj_i: (Iterable[Number], Number), + Vi_j: (Iterable[Number], Number), + Vj_j: (Iterable[Number], Number), + C0: float = 0, + verbose: bool = False, + ) -> float: """ _calculate_optimize this function is calculating the free energy difference of two states with the BAR method. @@ -626,21 +687,26 @@ def _calculate_optimize(self, Vi_i: (Iterable[Number], Number), Vj_i: (Iterable[ float free energy difference """ - if ( - not ((len(Vi_i) == len(Vi_i)) and ( - len(Vi_j) == len(Vj_j)))): # I and J simulation don't need the same length. + if not ( + (len(Vi_i) == len(Vi_i)) and (len(Vi_j) == len(Vj_j)) + ): # I and J simulation don't need the same length. raise ValueError( - "Zwanzig Error: The given arrays for Vi and Vj must have the same length. \n Actually they have: " + str( - len(Vi_i) + " \t " + str(len(Vj_i))) + "\n" + str(len(Vi_j) + " \t " + str(len(Vj_j))) + "\n") + "Zwanzig Error: The given arrays for Vi and Vj must have the same length. \n Actually they have: " + + str(len(Vi_i) + " \t " + str(len(Vj_i))) + + "\n" + + str(len(Vi_j) + " \t " + str(len(Vj_j))) + + "\n" + ) # Calc Beta self.constants.update({self.beta: 1 / (self.constants[self.k] * self.constants[self.T])}) # given C? - if (not isinstance(C0, type(None))): + if not isinstance(C0, type(None)): self.constants.update({self.C: C0}) # optimization scheme: - if (verbose): print("Iterate: \tconvergence raidus: " + str(self.convergence_radius)) + if verbose: + print("Iterate: \tconvergence raidus: " + str(self.convergence_radius)) iteration = 0 convergence = self.convergence_radius + 1 while self.max_iterations > iteration: @@ -650,17 +716,19 @@ def _calculate_optimize(self, Vi_i: (Iterable[Number], Number), Vj_i: (Iterable[ newC = dF convergence = abs(self.constants[self.C] - dF) - if (verbose): print("Iteration: " + str(iteration) + "\tdF: " + str(dF), "\tconvergence", convergence) + if verbose: + print("Iteration: " + str(iteration) + "\tdF: " + str(dF), "\tconvergence", convergence) - if (convergence > self.convergence_radius or self.min_iterations > iteration): + if convergence > self.convergence_radius or self.min_iterations > iteration: iteration += 1 self.constants.update({self.C: newC}) else: break print() - if (iteration >= self.max_iterations): + if iteration >= self.max_iterations: raise Exception( - "BAR is not converged after " + str(iteration) + " steps. stopped at: " + str(self.constants[self.C])) + "BAR is not converged after " + str(iteration) + " steps. stopped at: " + str(self.constants[self.C]) + ) print("Final Iterations: ", iteration, " Result: ", dF) return float(dF) @@ -678,13 +746,13 @@ def set_parameters(self, C: float = None, T: float = None, k: float = None): C is the initial guess of the free energy difference. """ - if (isinstance(T, Number)): + if isinstance(T, Number): self.constants.update({self.T: T}) - if (isinstance(k, Number)): + if isinstance(k, Number): self.constants.update({self.k: k}) - if (isinstance(C, Number)): + if isinstance(C, Number): self.constants.update({self.C: C}) self._update_function() diff --git a/pygromos/data/__init__.py b/pygromos/data/__init__.py index 6429950f..58331d00 100644 --- a/pygromos/data/__init__.py +++ b/pygromos/data/__init__.py @@ -3,5 +3,6 @@ """ import os + data_dir = os.path.dirname(__file__) -pdb_lib = data_dir+"/pdb2g96.lib" +pdb_lib = data_dir + "/pdb2g96.lib" diff --git a/pygromos/data/ene_ana_libs/__init__.py b/pygromos/data/ene_ana_libs/__init__.py index be6ebdb6..76b91200 100644 --- a/pygromos/data/ene_ana_libs/__init__.py +++ b/pygromos/data/ene_ana_libs/__init__.py @@ -1,2 +1,3 @@ import os -std_ene_ana_lib =os.path.dirname(__file__)+"/ene_ana.md++.lib" + +std_ene_ana_lib = os.path.dirname(__file__) + "/ene_ana.md++.lib" diff --git a/pygromos/data/ene_ana_libs/ene_ana.md++.lib b/pygromos/data/ene_ana_libs/ene_ana.md++.lib index 4d028018..d041f25a 100644 --- a/pygromos/data/ene_ana_libs/ene_ana.md++.lib +++ b/pygromos/data/ene_ana_libs/ene_ana.md++.lib @@ -29,7 +29,7 @@ ENERTRJ subblock NONBONDED matrix_NUM_ENERGY_GROUPS 4 subblock SPECIAL NUM_ENERGY_GROUPS 11 size NUM_EDS_STATES - subblock EDS NUM_EDS_STATES 4 + subblock EDS NUM_EDS_STATES 4 size NUM_LAMBDAS subblock PRECALCLAM NUM_LAMBDAS 11 subblock ABDIH 1 2 @@ -74,7 +74,7 @@ VARIABLES # the MASS which (if not present in the energy trajectory) will be calculated # from the topology (if inputflag @topo is given). # -# Additional properties can be defined here as a direct mapping of a known +# Additional properties can be defined here as a direct mapping of a known # property or as an expression of such properties. Make sure that variables # and operators are always seperated by spaces. Multi-line expressions are # allowed. @@ -155,21 +155,21 @@ solvtemp3 = TEMPERATURE[3][1] # Hvap = Ugas - Uliq + RT # # where Ugas and Uliq are the total potential energies -# of a single molecule in the gas and liquid phase, respectively, +# of a single molecule in the gas and liquid phase, respectively, # R denotes the gas constant and T the absolute temperature. -# To calculate Hvap from an energy trajectory obtained -# from a condensed phase simulation, Ugas = GASENER +# To calculate Hvap from an energy trajectory obtained +# from a condensed phase simulation, Ugas = GASENER # has to be provided (e.g. from a separate simulation) -# along with the number of molecules, NUMMOL, in the box +# along with the number of molecules, NUMMOL, in the box # and the temperature TEMP, e.g: # # TEMP = 300.0 # GASENER = 0 # NUMMOL = 512 # hvap = GASENER - ENER[3] / NUMMOL + BOLTZ * TEMP -# -# Alternatively the temperature can be made available -# from the appropriate entry in the TEMPERATURE +# +# Alternatively the temperature can be made available +# from the appropriate entry in the TEMPERATURE # subblock. # # VISCOSITY (used by visco program) @@ -182,5 +182,4 @@ offP3 = PRESSURE[9] offP4 = PRESSURE[7] offP5 = PRESSURE[10] offP6 = PRESSURE[11] -END - +END diff --git a/pygromos/data/ff/Gromos2016H66/2016H66.ifp b/pygromos/data/ff/Gromos2016H66/2016H66.ifp index 68ea7dbe..27a3215b 100644 --- a/pygromos/data/ff/Gromos2016H66/2016H66.ifp +++ b/pygromos/data/ff/Gromos2016H66/2016H66.ifp @@ -2,25 +2,25 @@ TITLE File : 2016H66.ifp Force field : 2016H66 (condensed-phase simulations) Reference : B.A.C. Horta, P.T. Merz, P.F.J. Fuchs, J. Dolenc, S. Riniker & P.H. Hunenberger - A GROMOS-compatible force field for small organic molecules in the condensed + A GROMOS-compatible force field for small organic molecules in the condensed phase: The 2016H66 parameter set; J. Chem. Theory. Comput. 2016 File content : Interaction function parameters Format : GROMOS11 Initial file : BACH/Rio+PHH/Zuerich, May 2016 Time stamp : PHH, Sun May 29 09:54:41 CEST 2016 -Remark : The force field 2016H66 was calibrated and validated for 57 organic liquids - + 5 nucleic acid bases (see mtb file "_orga", which also contains the solvent cyclohexane); - biomolecular files are also provided as described in the Appendix of Suppl Mat A of +Remark : The force field 2016H66 was calibrated and validated for 57 organic liquids + + 5 nucleic acid bases (see mtb file "_orga", which also contains the solvent cyclohexane); + biomolecular files are also provided as described in the Appendix of Suppl Mat A of the above reference (see also the headers of the individual mtb files); however ************************************************************************************ ****** keep in mind that this biomolecular component has only undergone ****** ****** preliminary tests and not yet a thorough validation! ****** ************************************************************************************ -Remark : make_top must recognize negative dihedral-angle type codes in patches, - which indicate that, if present, an existing dihedral angle with the given type +Remark : make_top must recognize negative dihedral-angle type codes in patches, + which indicate that, if present, an existing dihedral angle with the given type code must be removed (used in HO2C, HO3C, HO4C, HO6C and C1OH patches for - carbohydrates to delete existing T2 or T6/T7 dihedrals assuming a OC instead of - a OH); for this reason + carbohydrates to delete existing T2 or T6/T7 dihedrals assuming a OC instead of + a OH); for this reason ************************************************************************************ ****** topologies must be built using a make_top version of June 2012 or later ***** ************************************************************************************ @@ -109,7 +109,7 @@ END MASSATOMTYPECODE # # --- The mass types of 2016H66 are identical to those of 53A6 -# except for the addition of LI, K, RB, CS, BR and I +# except for the addition of LI, K, RB, CS, BR and I # # NRMATY NMATY 26 133 @@ -153,7 +153,7 @@ END BONDSTRETCHTYPECODE # # --- The bond-stretching types of 2016H66 are identical to those of 53A6 -# but their usage has been slightly modified for the oxygen +# but their usage has been slightly modified for the oxygen # chemical functions according to the 53A6_OXY force field # (Horta et al. J. Chem. Theory Comput. 2011, 7, 1016-1031); # these slight differences of assignments between 53A6 and @@ -333,7 +333,7 @@ END BONDANGLEBENDTYPECODE # # --- The bond-angle-bending types of 2016H66 are identical to those of 53A6 -# but their usage has been slightly modified for the oxygen +# but their usage has been slightly modified for the oxygen # chemical functions according to the 53A6_OXY force field # (Horta et al. J. Chem. Theory Comput. 2011, 7, 1016-1031); # these slight differences of assignments between 53A6 and @@ -557,9 +557,9 @@ TORSDIHEDRALTYPECODE # 53A6_OXY+D (types 42-46; Fuchs et al. J. Chem. Theory Comput. 2012, 8, 3943-3963), # 56A6_CARBO (types 48-60; Hansen & Hunenberger, J. Comput. Chem. 2011, 32, 998-1032), # and 56A6_CARBO-R (types 61-62; Plazinski et al., J. Comput. Chem. 2016, 37, 354-365). -# Note that 54A7 consisted of the 41 types of 53A6 + 4 additional -# types for phi/psi peptide patches (numbered 42-45 in the 54A7 files); -# these have been deleted. Instead, a new type (type 48) has been +# Note that 54A7 consisted of the 41 types of 53A6 + 4 additional +# types for phi/psi peptide patches (numbered 42-45 in the 54A7 files); +# these have been deleted. Instead, a new type (type 48) has been # added here in replacement, corresponding to a single phi peptide patch. # # NRPTY NPTY @@ -708,7 +708,7 @@ TORSDIHEDRALTYPECODE 41 3.770 0.0 6 # -CHn-NT- 0.9 # -# The next 6 entries are from 53A6_OXY+D; the D-index refers to +# The next 6 entries are from 53A6_OXY+D; the D-index refers to # Table 4 of Fuchs et al., J. Comput. Chem. 2012, 8, 3943-3963 # 42 0.931 180.0 1 @@ -729,16 +729,16 @@ TORSDIHEDRALTYPECODE 47 6.787 0.0 3 # OE-CHn-CHn-OE (D6 in OXY+D) 1.62 # -# The next entry is specific to 2016H66; it corresponds to the phi patch for the protein backbone, +# The next entry is specific to 2016H66; it corresponds to the phi patch for the protein backbone, # see Appendix of Suppl Mat A of Horta et al. 2016 (the 2016H66 article) -# +# 48 3.000 0.0 3 # -CHn-N,NE- (phi-patch) 0.71 # -# The next 12 entries are from 56A6_CARBO; the T-index refers to +# The next 12 entries are from 56A6_CARBO; the T-index refers to # to Table 6 of Hansen & Hunenberger, J. Comput. Chem. 2011, 32, 998-1032 # -# Type T1 is already listed above as type 34 +# Type T1 is already listed above as type 34 # 34 5.920 0.0 3 # T1 : 56A6_CARBO X-C-C-X; X not H (generic CC - unaltered from 53A6) # @@ -778,8 +778,8 @@ TORSDIHEDRALTYPECODE 60 1.000 180.0 1 # T13: 56A6_CARBO Ox-X-X-Or (oxygen-oxygen intracyclic) # -# The next 2 entries are from 56A6_CARBO-R; the T5R-index refers to -# the variants of T5 introduced in the Section "Force-field parameters" +# The next 2 entries are from 56A6_CARBO-R; the T5R-index refers to +# the variants of T5 introduced in the Section "Force-field parameters" # of Plazinski et al., J. Comput. Chem. 2016, 37, 354-365 # 61 4.500 180.0 1 @@ -792,13 +792,13 @@ END # SINGLEATOMLJPAIR # -# --- The atom types of 2016H66 are gathered from 53A6 (types 1-53), 54A7 (type 54), -# alkali and halide ions (types 55-63; set L in Reif and Hunenberger, -# J. Chem. Phys. 2011, 134, 144104) and 56A6_CARBO (types 64-66; +# --- The atom types of 2016H66 are gathered from 53A6 (types 1-53), 54A7 (type 54), +# alkali and halide ions (types 55-63; set L in Reif and Hunenberger, +# J. Chem. Phys. 2011, 134, 144104) and 56A6_CARBO (types 64-66; # Hansen & Hunenberger, J. Comput. Chem. 2011, 32, 998-1032). # # Among the first 53 atom types, the Lennard-Jones interaction parameters -# of only 8 types (O, OA, OE, N, NT, NR, CH2r and S) have been modified +# of only 8 types (O, OA, OE, N, NT, NR, CH2r and S) have been modified # relative to 53A6, as described in Horta et al. 2016 (the 2016H66 article). # For the remaining 13 atom types, the Lennard-Jones interaction parameters # are the same as in the original references. @@ -821,10 +821,10 @@ SINGLEATOMLJPAIR # third-neighbor square-root Lennard-Jones interaction parameters # selection matrix for the repulsive Lennard-Jones interaction parameters # -# selection matrix: for a first atom of type I (line) and a second atom of -# type J (column), the M(I,J) and M(J,I) entries (1, 2 or 3) specify that in -# the combination rule for C12, SQRT{C12[M(I,J)]} will be taken for atom I -# and SQRT{C12[M(J,I)]} will will be taken for atom J (note that the matrix +# selection matrix: for a first atom of type I (line) and a second atom of +# type J (column), the M(I,J) and M(J,I) entries (1, 2 or 3) specify that in +# the combination rule for C12, SQRT{C12[M(I,J)]} will be taken for atom I +# and SQRT{C12[M(J,I)]} will will be taken for atom J (note that the matrix # is not symmetric) # # IAC TYPE SQRT(C6) SQRT(C12(1)) SQRT(C12(2)) SQRT(C12(3)) @@ -1118,7 +1118,7 @@ SINGLEATOMLJPAIR #--- 37 NA+ 0.008489 0.1450E-3 0.1450E-3 0.0 #CS6 CS12 parameters LJ14PAIR - 0.008489 0.1450E-3 + 0.008489 0.1450E-3 2 2 2 2 2 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 1 2 1 2 1 1 1 1 1 2 1 1 2 1 1 1 1 2 1 1 1 1 1 1 1 2 @@ -1126,7 +1126,7 @@ SINGLEATOMLJPAIR #--- 38 CL- 0.1175 10.340E-3 10.340E-3 10.340E-3 #CS6 CS12 parameters LJ14PAIR - 0.1175 10.340E-3 + 0.1175 10.340E-3 1 1 2 1 2 2 2 3 2 3 3 1 1 1 1 1 1 1 1 1 1 1 1 3 3 3 3 3 3 3 1 1 1 1 1 2 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 3 3 3 3 3 1 @@ -1332,7 +1332,7 @@ SINGLEATOMLJPAIR 1 1 1 1 1 1 1 1 1 1 1 1 2 1 3 3 3 3 3 1 1 1 1 1 1 1 #--- - 64 Or 0.04756 1.100E-3 1.227E-3 0.0 + 64 Or 0.04756 1.100E-3 1.227E-3 0.0 #CS6 CS12 parameters LJ14PAIR 0.04756 0.685E-3 1 1 2 1 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 @@ -1340,21 +1340,21 @@ SINGLEATOMLJPAIR 1 1 1 1 1 1 1 1 1 1 1 1 2 1 2 2 2 2 2 1 1 1 1 1 1 1 #--- - 65 CH0r 0.04896 14.330E-3 0.0 0.0 -#CS6 CS12 parameters LJ14PAIR for now using 1-4 params as for CH2r + 65 CH0r 0.04896 14.330E-3 0.0 0.0 +#CS6 CS12 parameters LJ14PAIR for now using 1-4 params as for CH2r 0.06873 1.36E-3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 + 1 1 1 1 1 1 #--- - 66 CH1r 0.07790 9.850E-3 0.0 0.0 -#CS6 CS12 parameters LJ14PAIR for now using 1-4 params as for CH2r + 66 CH1r 0.07790 9.850E-3 0.0 0.0 +#CS6 CS12 parameters LJ14PAIR for now using 1-4 params as for CH2r 0.06873 1.36E-3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 + 1 1 1 1 1 1 #--- END # @@ -1372,19 +1372,19 @@ SPECATOMLJPAIR # # --- The Lennard-Jones exception types of 2016H66 only concern the carbohydrates, and # are those of 56A6_CARBO-R (Plazinski et al., J. Comput. Chem. 2016, 37, 354-365); -# the first five originate from 56A6_CARBO (Hansen & Hunenberger, J. Comput. Chem. +# the first five originate from 56A6_CARBO (Hansen & Hunenberger, J. Comput. Chem. # 2011, 32, 998-1032), and the last one was added in 56A6_CARBO-R. # # # TYPE C12 C6 # -# The first 5 entries are from 53A6_CARBO; the N-index refers to +# The first 5 entries are from 53A6_CARBO; the N-index refers to # Table 5 of Hansen & Hunenberger, J. Comput. Chem. 2011, 32, 998-1032 # - 1 0.70E-6 0.0 + 1 0.70E-6 0.0 # N1: 56A6_CARBO H-O-X-Or (lactol) # - 2 0.35E-6 0.0 + 2 0.35E-6 0.0 # N2: 56A6_CARBO H-O-Xr-Xr-Xr (hydroxyl) # 3 3.33986E-6 5.689469E-3 @@ -1396,8 +1396,8 @@ SPECATOMLJPAIR 5 8.4108E-6 4.110135E-3 # N5: 56A6_CARBO O-Xr-Xr-Xr-CH*r (Hassel-Ottar) # -# The last entry is from 53A6_CARBO-R; the N4R-index refers to -# the variant of N4 introduced in the Section "Force-field parameters" +# The last entry is from 53A6_CARBO-R; the N4R-index refers to +# the variant of N4 introduced in the Section "Force-field parameters" # of Plazinski et al., J. Comput. Chem. 2016, 37, 354-365 # 6 0.7E-6 3.268799E-3 diff --git a/pygromos/data/ff/Gromos2016H66/2016H66.mtb b/pygromos/data/ff/Gromos2016H66/2016H66.mtb index c0315260..f934e9e1 100644 --- a/pygromos/data/ff/Gromos2016H66/2016H66.mtb +++ b/pygromos/data/ff/Gromos2016H66/2016H66.mtb @@ -2,26 +2,26 @@ TITLE File : 2016H66.mtb Force field : 2016H66 (condensed-phase simulations) Reference : B.A.C. Horta, P.T. Merz, P.F.J. Fuchs, J. Dolenc, S. Riniker & P.H. Hunenberger - A GROMOS-compatible force field for small organic molecules in the condensed + A GROMOS-compatible force field for small organic molecules in the condensed phase: The 2016H66 parameter set; J. Chem. Theory. Comput. 2016 -File content : molecular topology building blocks (main file; PHYSICALCONSTANTS, LINKEXCLUSIONS, +File content : molecular topology building blocks (main file; PHYSICALCONSTANTS, LINKEXCLUSIONS, solvents, small species, ions) Format : GROMOS11 Initial file : BACH/Rio+PHH/Zuerich, May 2016 Time stamp : PHH, Sun May 29 09:54:41 CEST 2016 -Remark : The force field 2016H66 was calibrated and validated for 57 organic liquids - + 5 nucleic acid bases (see mtb file "_orga", which also contains the solvent cyclohexane); - biomolecular files are also provided as described in the Appendix of Suppl Mat A of +Remark : The force field 2016H66 was calibrated and validated for 57 organic liquids + + 5 nucleic acid bases (see mtb file "_orga", which also contains the solvent cyclohexane); + biomolecular files are also provided as described in the Appendix of Suppl Mat A of the above reference (see also the headers of the individual mtb files); however ************************************************************************************ ****** keep in mind that this biomolecular component has only undergone ****** ****** preliminary tests and not yet a thorough validation! ****** ************************************************************************************ -Remark : make_top must recognize negative dihedral-angle type codes in patches, - which indicate that, if present, an existing dihedral angle with the given type +Remark : make_top must recognize negative dihedral-angle type codes in patches, + which indicate that, if present, an existing dihedral angle with the given type code must be removed (used in HO2C, HO3C, HO4C, HO6C and C1OH patches for - carbohydrates to delete existing T2 or T6/T7 dihedrals assuming a OC instead of - a OH); for this reason + carbohydrates to delete existing T2 or T6/T7 dihedrals assuming a OC instead of + a OH); for this reason ************************************************************************************ ****** topologies must be built using a make_top version of June 2012 or later ***** ************************************************************************************ diff --git a/pygromos/data/ff/Gromos2016H66/2016H66_orga.mtb b/pygromos/data/ff/Gromos2016H66/2016H66_orga.mtb index 8a82d562..8987484a 100644 --- a/pygromos/data/ff/Gromos2016H66/2016H66_orga.mtb +++ b/pygromos/data/ff/Gromos2016H66/2016H66_orga.mtb @@ -2,25 +2,25 @@ TITLE File : 2016H66_orga.mtb Force field : 2016H66 (condensed-phase simulations) Reference : B.A.C. Horta, P.T. Merz, P.F.J. Fuchs, J. Dolenc, S. Riniker & P.H. Hunenberger - A GROMOS-compatible force field for small organic molecules in the condensed + A GROMOS-compatible force field for small organic molecules in the condensed phase: The 2016H66 parameter set; J. Chem. Theory. Comput. 2016 File content : molecular topology building blocks (small organic molecules) Format : GROMOS11 Initial file : BACH/Rio+PHH/Zuerich, May 2016 Time stamp : PHH, Sun May 29 09:54:41 CEST 2016 -Remark : The force field 2016H66 was calibrated and validated for 57 organic liquids - + 5 nucleic acid bases (see mtb file "_orga", which also contains the solvent cyclohexane); - biomolecular files are also provided as described in the Appendix of Suppl Mat A of +Remark : The force field 2016H66 was calibrated and validated for 57 organic liquids + + 5 nucleic acid bases (see mtb file "_orga", which also contains the solvent cyclohexane); + biomolecular files are also provided as described in the Appendix of Suppl Mat A of the above reference (see also the headers of the individual mtb files); however ************************************************************************************ ****** keep in mind that this biomolecular component has only undergone ****** ****** preliminary tests and not yet a thorough validation! ****** ************************************************************************************ -Remark : make_top must recognize negative dihedral-angle type codes in patches, - which indicate that, if present, an existing dihedral angle with the given type +Remark : make_top must recognize negative dihedral-angle type codes in patches, + which indicate that, if present, an existing dihedral angle with the given type code must be removed (used in HO2C, HO3C, HO4C, HO6C and C1OH patches for - carbohydrates to delete existing T2 or T6/T7 dihedrals assuming a OC instead of - a OH); for this reason + carbohydrates to delete existing T2 or T6/T7 dihedrals assuming a OC instead of + a OH); for this reason ************************************************************************************ ****** topologies must be built using a make_top version of June 2012 or later ***** ************************************************************************************ @@ -43,8 +43,8 @@ END # ----- Auxiliary mtb file: small organic molecules # This file contains 63 blocks # -# These are molecules relevant for the parametrization and calibration of -# 2016H66 in Horta et al. 2016 (the 2016H66 article), namely: one solvent +# These are molecules relevant for the parametrization and calibration of +# 2016H66 in Horta et al. 2016 (the 2016H66 article), namely: one solvent # (CHE, used for solvation free-energy calculations), 57 organic liquids # and 5 methylated nucleic-acid bases. # @@ -3038,7 +3038,7 @@ PHT 8 10 11 12 13 2 O1 3 16 -0.70000 0 7 3 4 5 6 10 12 13 - 3 H1 21 1 0.41000 1 0 + 3 H1 21 1 0.41000 1 0 4 C2 12 12 -0.12980 0 8 5 6 7 8 9 10 12 13 5 H2 20 1 0.12980 1 4 6 7 8 12 @@ -3310,10 +3310,10 @@ MADE #ATOM MAE MSAE # atoms #ATOM ANM IACM MASS CGMICGM MAE MSAE - 1 C9M 16 5 0.00000 1 7 2 3 4 12 13 14 + 1 C9M 16 5 0.00000 1 7 2 3 4 12 13 14 15 2 N9 9 14 -0.20000 0 8 3 4 5 8 12 13 - 14 15 + 14 15 3 C4 12 12 0.20000 1 10 4 5 6 7 8 9 12 13 14 15 4 N3 9 14 -0.56000 0 7 5 6 7 8 12 13 @@ -3422,14 +3422,14 @@ MGUA #ATOM MAE MSAE # atoms #ATOM ANM IACM MASS CGMICGM MAE MSAE - 1 C9M 16 5 0.00000 1 7 2 3 4 13 14 15 + 1 C9M 16 5 0.00000 1 7 2 3 4 13 14 15 16 - 2 N9 9 14 -0.20000 0 8 3 4 5 11 13 14 + 2 N9 9 14 -0.20000 0 8 3 4 5 11 13 14 15 16 - 3 C4 12 12 0.20000 1 10 4 5 6 9 11 12 + 3 C4 12 12 0.20000 1 10 4 5 6 9 11 12 13 14 15 16 - 4 N3 9 14 -0.53000 0 8 5 6 9 10 11 13 - 14 15 + 4 N3 9 14 -0.53000 0 8 5 6 9 10 11 13 + 14 15 5 C2 12 12 0.53000 1 8 6 7 8 9 10 11 12 13 6 N2 7 14 -0.80000 0 5 7 8 9 10 11 @@ -3496,7 +3496,7 @@ MGUA 14 15 16 36 # improper dihedrals # NIDA - 19 + 19 # IB JB KB LB MCB 2 1 3 15 1 3 2 4 13 1 @@ -3516,7 +3516,7 @@ MGUA 9 11 13 3 1 13 3 4 5 1 13 14 15 2 1 - 15 2 3 13 1 + 15 2 3 13 1 # dihedrals # NDA 1 @@ -3533,28 +3533,28 @@ MTBUILDBLSOLUTE MTHY # number of atoms, number of preceding exclusions # NMAT,NLIN - 12 0 + 12 0 # preceding exclusions #ATOM MAE MSAE # atoms #ATOM ANM IACM MASS CGMICGM MAE MSAE 1 C1M 16 5 0.00000 1 7 2 3 4 5 6 7 11 2 N1 9 14 -0.20000 0 9 3 4 5 6 7 8 9 - 11 12 - 3 C6 12 12 0.10000 0 8 4 5 6 7 9 10 11 - 12 - 4 H6 20 1 0.10000 1 4 5 9 11 12 - 5 C2 12 12 0.48000 0 6 6 7 8 9 10 11 - 6 O2 1 16 -0.48000 1 3 7 8 9 - 7 N3 9 14 -0.32000 0 5 8 9 10 11 12 - 8 H3 21 1 0.32000 1 3 9 10 11 + 11 12 + 3 C6 12 12 0.10000 0 8 4 5 6 7 9 10 11 + 12 + 4 H6 20 1 0.10000 1 4 5 9 11 12 + 5 C2 12 12 0.48000 0 6 6 7 8 9 10 11 + 6 O2 1 16 -0.48000 1 3 7 8 9 + 7 N3 9 14 -0.32000 0 5 8 9 10 11 12 + 8 H3 21 1 0.32000 1 3 9 10 11 9 C4 12 12 0.48000 0 3 10 11 12 - 10 O4 1 16 -0.48000 1 2 11 12 - 11 C5 12 12 0.00000 0 1 12 + 10 O4 1 16 -0.48000 1 2 11 12 + 11 C5 12 12 0.00000 0 1 12 12 C5M 16 5 0.00000 1 0 # bonds # NB - 12 + 12 # IB JB MCB 1 2 23 2 3 17 @@ -3608,7 +3608,7 @@ MTHY 11 3 9 12 1 # dihedrals # NDA - 0 + 0 # IB JB KB LB MCB # LJ exceptions # NEX @@ -3626,7 +3626,7 @@ MCYT #ATOM MAE MSAE # atoms #ATOM ANM IACM MASS CGMICGM MAE MSAE - 1 C1M 16 5 0.00000 1 7 2 3 4 5 6 7 + 1 C1M 16 5 0.00000 1 7 2 3 4 5 6 7 12 2 N1 9 14 -0.20000 0 8 3 4 5 6 7 8 12 13 @@ -3637,7 +3637,7 @@ MCYT 6 O2 1 16 -0.44000 1 2 7 8 7 N3 9 14 -0.53000 0 4 8 9 12 13 8 C4 12 12 0.53000 1 5 9 10 11 12 13 - 9 N4 7 14 -0.80000 0 4 10 11 12 13 + 9 N4 7 14 -0.80000 0 4 10 11 12 13 10 H41 21 1 0.40000 0 1 11 11 H42 21 1 0.40000 1 0 12 C5 12 12 -0.10000 0 1 13 @@ -3721,10 +3721,10 @@ MURA #ATOM MAE MSAE # atoms #ATOM ANM IACM MASS CGMICGM MAE MSAE - 1 C1M 16 5 0.00000 1 7 2 3 4 5 6 7 + 1 C1M 16 5 0.00000 1 7 2 3 4 5 6 7 11 2 N1 9 14 -0.20000 0 9 3 4 5 6 7 8 - 9 11 12 + 9 11 12 3 C6 12 12 0.10000 0 8 4 5 6 7 9 10 11 12 4 H6 20 1 0.10000 1 4 5 9 11 12 diff --git a/pygromos/data/ff/Gromos2016H66/__init__.py b/pygromos/data/ff/Gromos2016H66/__init__.py index e87905c8..e8d179c6 100644 --- a/pygromos/data/ff/Gromos2016H66/__init__.py +++ b/pygromos/data/ff/Gromos2016H66/__init__.py @@ -1,5 +1,6 @@ import os + ff_dir = os.path.dirname(__file__) -ifp = ff_dir+"/2016H66.ifp" -mtb = ff_dir+"/2016H66.mtb" -mtb_orga = ff_dir+"/2016H66_orga.mtb" \ No newline at end of file +ifp = ff_dir + "/2016H66.ifp" +mtb = ff_dir + "/2016H66.mtb" +mtb_orga = ff_dir + "/2016H66_orga.mtb" diff --git a/pygromos/data/ff/Gromos54A7/54a7.ifp b/pygromos/data/ff/Gromos54A7/54a7.ifp index 1e2ca5e2..059f5b84 100755 --- a/pygromos/data/ff/Gromos54A7/54a7.ifp +++ b/pygromos/data/ff/Gromos54A7/54a7.ifp @@ -20,12 +20,12 @@ PHH, 06.06.2011: Small correction in comments (carbohydrate dihedrals) - data un PHH, 09.11.2011: Reintroduced a FORCEFIELD block in all GROMOS11 files. PHH, 26.06.2012: Introduced MAKETOPVERSION blocks in all GROMOS11 files PHH, 08.04.2013: Upon conversion of 45A4 to 53A5, which involved a renumbering of the - dihedral-angle types, type 37 was mapped to renumbered dihedral type 3 - (sugar: O5-C5-C6-O6, omega-tilde dihedral, for residue with syn C4,C5 - like Gal, 1-fold term), but with an incorrect force constant of 4.97 - instead of 6.66; this is now corrected in the ifp files of 53A5 and - later versions (dihedral type 3 is not used in any other residue; - this problem does not affect the new carbohydrate force field + dihedral-angle types, type 37 was mapped to renumbered dihedral type 3 + (sugar: O5-C5-C6-O6, omega-tilde dihedral, for residue with syn C4,C5 + like Gal, 1-fold term), but with an incorrect force constant of 4.97 + instead of 6.66; this is now corrected in the ifp files of 53A5 and + later versions (dihedral type 3 is not used in any other residue; + this problem does not affect the new carbohydrate force field 56A6@CARBO, which does not use this dihedral) END FORCEFIELD diff --git a/pygromos/data/ff/Gromos54A7/54a7.mtb b/pygromos/data/ff/Gromos54A7/54a7.mtb index 1b96bbda..4d91b78e 100755 --- a/pygromos/data/ff/Gromos54A7/54a7.mtb +++ b/pygromos/data/ff/Gromos54A7/54a7.mtb @@ -23,7 +23,7 @@ PHH, 15.09.2011: Corrected the phi/psi dihedral potentials for residue AIB in th PHH, 15.09.2011: Corrected the atom charges for residue DPPC in the G96 and G11 54A7 mtb files (they had not been updated from 53A6; found by Alpesh Malde). Note that the DPPC charges in 54B7 are kept the same as in 53B6, i.e. not updated (they differ - between 53A6 and 54A7, and the definition of a scheme for designing new 54B7 charges + between 53A6 and 54A7, and the definition of a scheme for designing new 54B7 charges is neither obvious nor really urgent). PHH, 09.11.2011: Reintroduced a FORCEFIELD block in all GROMOS11 files. PHH, 09.11.2011: Changed atom name H3 by H2 in NH2 patch. @@ -32,10 +32,10 @@ PHH, 22.11.2011: Finalized the #@BLOCKTYPE comments in mtb files listing file na code (BLK=...), function (SOL,INI,TER,SVT), type (TYPE=APEP,BPEP,DNUC,RNUC, HEXP,HEXU,MOLE), and full name (NAME=...): intended for later use by make_top. PHH, 26.06.2012: Introduced MAKETOPVERSION blocks in all GROMOS11 files -PHH, 12.07.2012: Removed all LINKEXCLUSIONS and PHYSICALCONSTANTS blocks from GROMOS11 - auxiliary mtb files (now only included in the main mtb file). As a result +PHH, 12.07.2012: Removed all LINKEXCLUSIONS and PHYSICALCONSTANTS blocks from GROMOS11 + auxiliary mtb files (now only included in the main mtb file). As a result (and also since MTBUILBLSOLVENT is only to be found there), make_top must - always be called with inclusion of the main mtb file (in addition to + always be called with inclusion of the main mtb file (in addition to the possible auxiliary ones). PHH, 01.05.2013: New N-terminal patches GH3+ and GH2 for alpha-peptides; these are meant to precede a residue where CA is a CH2 diff --git a/pygromos/data/ff/Gromos54A7/__init__.py b/pygromos/data/ff/Gromos54A7/__init__.py index a9c2892e..9f1f40b0 100644 --- a/pygromos/data/ff/Gromos54A7/__init__.py +++ b/pygromos/data/ff/Gromos54A7/__init__.py @@ -1,4 +1,5 @@ import os + ff_dir = os.path.dirname(__file__) -ifp = ff_dir+"/54a7.ifp" -mtb = ff_dir+"/54a7.mtb" \ No newline at end of file +ifp = ff_dir + "/54a7.ifp" +mtb = ff_dir + "/54a7.mtb" diff --git a/pygromos/data/ff/MixHexGromos54A7/2016H66_hex.mtb b/pygromos/data/ff/MixHexGromos54A7/2016H66_hex.mtb index 345efcd2..a5cf21aa 100644 --- a/pygromos/data/ff/MixHexGromos54A7/2016H66_hex.mtb +++ b/pygromos/data/ff/MixHexGromos54A7/2016H66_hex.mtb @@ -2,25 +2,25 @@ TITLE File : 2016H66_orga.mtb Force field : 2016H66 (condensed-phase simulations) Reference : B.A.C. Horta, P.T. Merz, P.F.J. Fuchs, J. Dolenc, S. Riniker & P.H. Hunenberger - A GROMOS-compatible force field for small organic molecules in the condensed + A GROMOS-compatible force field for small organic molecules in the condensed phase: The 2016H66 parameter set; J. Chem. Theory. Comput. 2016 File content : molecular topology building blocks (small organic molecules) Format : GROMOS11 Initial file : BACH/Rio+PHH/Zuerich, May 2016 Time stamp : PHH, Sun May 29 09:54:41 CEST 2016 -Remark : The force field 2016H66 was calibrated and validated for 57 organic liquids - + 5 nucleic acid bases (see mtb file "_orga", which also contains the solvent cyclohexane); - biomolecular files are also provided as described in the Appendix of Suppl Mat A of +Remark : The force field 2016H66 was calibrated and validated for 57 organic liquids + + 5 nucleic acid bases (see mtb file "_orga", which also contains the solvent cyclohexane); + biomolecular files are also provided as described in the Appendix of Suppl Mat A of the above reference (see also the headers of the individual mtb files); however ************************************************************************************ ****** keep in mind that this biomolecular component has only undergone ****** ****** preliminary tests and not yet a thorough validation! ****** ************************************************************************************ -Remark : make_top must recognize negative dihedral-angle type codes in patches, - which indicate that, if present, an existing dihedral angle with the given type +Remark : make_top must recognize negative dihedral-angle type codes in patches, + which indicate that, if present, an existing dihedral angle with the given type code must be removed (used in HO2C, HO3C, HO4C, HO6C and C1OH patches for - carbohydrates to delete existing T2 or T6/T7 dihedrals assuming a OC instead of - a OH); for this reason + carbohydrates to delete existing T2 or T6/T7 dihedrals assuming a OC instead of + a OH); for this reason ************************************************************************************ ****** topologies must be built using a make_top version of June 2012 or later ***** ************************************************************************************ @@ -43,8 +43,8 @@ END # ----- Auxiliary mtb file: small organic molecules # This file contains 63 blocks # -# These are molecules relevant for the parametrization and calibration of -# 2016H66 in Horta et al. 2016 (the 2016H66 article), namely: one solvent +# These are molecules relevant for the parametrization and calibration of +# 2016H66 in Horta et al. 2016 (the 2016H66 article), namely: one solvent # (CHE, used for solvation free-energy calculations), 57 organic liquids # and 5 methylated nucleic-acid bases. # diff --git a/pygromos/data/ff/MixHexGromos54A7/54a7.mtb b/pygromos/data/ff/MixHexGromos54A7/54a7.mtb index 1b96bbda..4d91b78e 100755 --- a/pygromos/data/ff/MixHexGromos54A7/54a7.mtb +++ b/pygromos/data/ff/MixHexGromos54A7/54a7.mtb @@ -23,7 +23,7 @@ PHH, 15.09.2011: Corrected the phi/psi dihedral potentials for residue AIB in th PHH, 15.09.2011: Corrected the atom charges for residue DPPC in the G96 and G11 54A7 mtb files (they had not been updated from 53A6; found by Alpesh Malde). Note that the DPPC charges in 54B7 are kept the same as in 53B6, i.e. not updated (they differ - between 53A6 and 54A7, and the definition of a scheme for designing new 54B7 charges + between 53A6 and 54A7, and the definition of a scheme for designing new 54B7 charges is neither obvious nor really urgent). PHH, 09.11.2011: Reintroduced a FORCEFIELD block in all GROMOS11 files. PHH, 09.11.2011: Changed atom name H3 by H2 in NH2 patch. @@ -32,10 +32,10 @@ PHH, 22.11.2011: Finalized the #@BLOCKTYPE comments in mtb files listing file na code (BLK=...), function (SOL,INI,TER,SVT), type (TYPE=APEP,BPEP,DNUC,RNUC, HEXP,HEXU,MOLE), and full name (NAME=...): intended for later use by make_top. PHH, 26.06.2012: Introduced MAKETOPVERSION blocks in all GROMOS11 files -PHH, 12.07.2012: Removed all LINKEXCLUSIONS and PHYSICALCONSTANTS blocks from GROMOS11 - auxiliary mtb files (now only included in the main mtb file). As a result +PHH, 12.07.2012: Removed all LINKEXCLUSIONS and PHYSICALCONSTANTS blocks from GROMOS11 + auxiliary mtb files (now only included in the main mtb file). As a result (and also since MTBUILBLSOLVENT is only to be found there), make_top must - always be called with inclusion of the main mtb file (in addition to + always be called with inclusion of the main mtb file (in addition to the possible auxiliary ones). PHH, 01.05.2013: New N-terminal patches GH3+ and GH2 for alpha-peptides; these are meant to precede a residue where CA is a CH2 diff --git a/pygromos/data/ff/MixHexGromos54A7/54a7_hex.ifp b/pygromos/data/ff/MixHexGromos54A7/54a7_hex.ifp index 78a61f21..0c64b568 100644 --- a/pygromos/data/ff/MixHexGromos54A7/54a7_hex.ifp +++ b/pygromos/data/ff/MixHexGromos54A7/54a7_hex.ifp @@ -20,12 +20,12 @@ PHH, 06.06.2011: Small correction in comments (carbohydrate dihedrals) - data un PHH, 09.11.2011: Reintroduced a FORCEFIELD block in all GROMOS11 files. PHH, 26.06.2012: Introduced MAKETOPVERSION blocks in all GROMOS11 files PHH, 08.04.2013: Upon conversion of 45A4 to 53A5, which involved a renumbering of the - dihedral-angle types, type 37 was mapped to renumbered dihedral type 3 - (sugar: O5-C5-C6-O6, omega-tilde dihedral, for residue with syn C4,C5 - like Gal, 1-fold term), but with an incorrect force constant of 4.97 - instead of 6.66; this is now corrected in the ifp files of 53A5 and - later versions (dihedral type 3 is not used in any other residue; - this problem does not affect the new carbohydrate force field + dihedral-angle types, type 37 was mapped to renumbered dihedral type 3 + (sugar: O5-C5-C6-O6, omega-tilde dihedral, for residue with syn C4,C5 + like Gal, 1-fold term), but with an incorrect force constant of 4.97 + instead of 6.66; this is now corrected in the ifp files of 53A5 and + later versions (dihedral type 3 is not used in any other residue; + this problem does not affect the new carbohydrate force field 56A6@CARBO, which does not use this dihedral) END FORCEFIELD diff --git a/pygromos/data/ff/MixHexGromos54A7/__init__.py b/pygromos/data/ff/MixHexGromos54A7/__init__.py index a42ca5b7..05b1e28b 100644 --- a/pygromos/data/ff/MixHexGromos54A7/__init__.py +++ b/pygromos/data/ff/MixHexGromos54A7/__init__.py @@ -1,5 +1,6 @@ import os + ff_dir = os.path.dirname(__file__) -ifp = ff_dir+"/54a7_hex.ifp" -mtb = ff_dir+"/54a7.mtb" -mtb_hex = ff_dir+"/2016H66_hex.mtb" \ No newline at end of file +ifp = ff_dir + "/54a7_hex.ifp" +mtb = ff_dir + "/54a7.mtb" +mtb_hex = ff_dir + "/2016H66_hex.mtb" diff --git a/pygromos/data/ff/SMIRNOFF/openff-1.3.0.offxml b/pygromos/data/ff/SMIRNOFF/openff-1.3.0.offxml index a50936e4..ea751b24 100644 --- a/pygromos/data/ff/SMIRNOFF/openff-1.3.0.offxml +++ b/pygromos/data/ff/SMIRNOFF/openff-1.3.0.offxml @@ -194,13 +194,13 @@ - + - + @@ -371,4 +371,4 @@ - \ No newline at end of file + diff --git a/pygromos/data/ff/SMIRNOFF/openff-2.0.0.offxml b/pygromos/data/ff/SMIRNOFF/openff-2.0.0.offxml index 070053dd..2a432101 100755 --- a/pygromos/data/ff/SMIRNOFF/openff-2.0.0.offxml +++ b/pygromos/data/ff/SMIRNOFF/openff-2.0.0.offxml @@ -371,4 +371,4 @@ - \ No newline at end of file + diff --git a/pygromos/data/ff/SMIRNOFF/openff_unconstrained-2.0.0.offxml b/pygromos/data/ff/SMIRNOFF/openff_unconstrained-2.0.0.offxml index 7aed4928..ed37c733 100644 --- a/pygromos/data/ff/SMIRNOFF/openff_unconstrained-2.0.0.offxml +++ b/pygromos/data/ff/SMIRNOFF/openff_unconstrained-2.0.0.offxml @@ -370,4 +370,4 @@ - \ No newline at end of file + diff --git a/pygromos/data/ff/__init__.py b/pygromos/data/ff/__init__.py index 8ba4d3f7..0c5404c4 100644 --- a/pygromos/data/ff/__init__.py +++ b/pygromos/data/ff/__init__.py @@ -4,7 +4,8 @@ import os from pygromos import data + data_ff_dir = os.path.dirname(__file__) data_ff_GROMOS54A7 = data_ff_dir + "/Gromos54A7" data_ff_GROMOS2016H66 = data_ff_dir + "/Gromos2016H66" -data_ff_SMIRNOFF = data_ff_dir + "/SMIRNOFF" \ No newline at end of file +data_ff_SMIRNOFF = data_ff_dir + "/SMIRNOFF" diff --git a/pygromos/data/ff/addAtomType.py b/pygromos/data/ff/addAtomType.py index ce502afa..9d8c6113 100644 --- a/pygromos/data/ff/addAtomType.py +++ b/pygromos/data/ff/addAtomType.py @@ -2,277 +2,272 @@ from pygromos.data.ff.atomType import AtomType - def main(): - fileName = '54a7.ifp' - outName = 'NEW_FILE.ifp' - row1, row2, block = readFile(fileName) - - atomTypes = readBlock(block) - addAtomType(atomTypes, 1) + fileName = "54a7.ifp" + outName = "NEW_FILE.ifp" + row1, row2, block = readFile(fileName) - check(atomTypes) - - writeOut(row1, row2, atomTypes, fileName, outName) + atomTypes = readBlock(block) + addAtomType(atomTypes, 1) + check(atomTypes) + writeOut(row1, row2, atomTypes, fileName, outName) def readFile(fileName): - """ + """ - Parameters - ---------- - fileName + Parameters + ---------- + fileName - Returns - ------- + Returns + ------- - """ - lines = [] - row1 = 0 - row2 = 0 + """ + lines = [] + row1 = 0 + row2 = 0 - with open(fileName, 'r') as f: - lines = f.readlines() + with open(fileName, "r") as f: + lines = f.readlines() - lines = [row.strip().split() for row in lines] + lines = [row.strip().split() for row in lines] - for i in range(len(lines)): - if lines[i][0] == 'SINGLEATOMLJPAIR': - row1 = i - row2, block = getBlock(lines, i + 1) - return row1, row2, block + for i in range(len(lines)): + if lines[i][0] == "SINGLEATOMLJPAIR": + row1 = i + row2, block = getBlock(lines, i + 1) + return row1, row2, block def getBlock(lines, row): - """ + """ - Parameters - ---------- - lines - row + Parameters + ---------- + lines + row - Returns - ------- + Returns + ------- - """ - block = [] + """ + block = [] - for i in range(row, len(lines)): - if lines[i][0] == 'END': - return i, block - else: - if lines[i][0] != '#': - block.append(lines[i]) + for i in range(row, len(lines)): + if lines[i][0] == "END": + return i, block + else: + if lines[i][0] != "#": + block.append(lines[i]) def readBlock(block): - """ + """ + + Parameters + ---------- + block - Parameters - ---------- - block + Returns + ------- - Returns - ------- + """ + nAtoms = 0 + atomTypes = [] - """ - nAtoms = 0 - atomTypes = [] + for i in range(len(block)): + if block[i][0] == "#number": + nAtoms = block[i + 1][0] - for i in range(len(block)): - if block[i][0] == '#number': - nAtoms = block[i + 1][0] - - elif block[i][0] == '#CS6': - atm = getAtomType(block, i - 1) - atomTypes.append(atm) + elif block[i][0] == "#CS6": + atm = getAtomType(block, i - 1) + atomTypes.append(atm) - return atomTypes + return atomTypes def getAtomType(block, row): - """ + """ - Parameters - ---------- - block - row + Parameters + ---------- + block + row - Returns - ------- + Returns + ------- - """ - atomBlock = [] + """ + atomBlock = [] - for i in range(row, len(block)): - if block[i][0] == '#---': - break - else: - if block[i][0] != '#CS6': - atomBlock.append(block[i]) + for i in range(row, len(block)): + if block[i][0] == "#---": + break + else: + if block[i][0] != "#CS6": + atomBlock.append(block[i]) - atomNum = atomBlock[0][0] - atomName = atomBlock[0][1] - sqrtC06 = atomBlock[0][2] - sqrtC12_1 = atomBlock[0][3] - sqrtC12_2 = atomBlock[0][4] - sqrtC12_3 = atomBlock[0][5] + atomNum = atomBlock[0][0] + atomName = atomBlock[0][1] + sqrtC06 = atomBlock[0][2] + sqrtC12_1 = atomBlock[0][3] + sqrtC12_2 = atomBlock[0][4] + sqrtC12_3 = atomBlock[0][5] - sqrtC06NB = atomBlock[1][0] - sqrtC12NB = atomBlock[1][1] + sqrtC06NB = atomBlock[1][0] + sqrtC12NB = atomBlock[1][1] - matrix = [] - for i in range(2, len(atomBlock)): - for j in range(len(atomBlock[i])): - matrix.append(atomBlock[i][j]) + matrix = [] + for i in range(2, len(atomBlock)): + for j in range(len(atomBlock[i])): + matrix.append(atomBlock[i][j]) - atm = AtomType(atomNum, atomName, sqrtC06, sqrtC12_1, sqrtC12_2, sqrtC12_3, - sqrtC06NB, sqrtC12NB, matrix) + atm = AtomType(atomNum, atomName, sqrtC06, sqrtC12_1, sqrtC12_2, sqrtC12_3, sqrtC06NB, sqrtC12NB, matrix) - return atm + return atm def addAtomType(atomTypes, N): - """ + """ - Parameters - ---------- - atomTypes - N + Parameters + ---------- + atomTypes + N - Returns - ------- + Returns + ------- - """ - for i in range(1, N + 1): - # extend matrix of all existing atom type by 1 - for a in atomTypes: - a.addToMatrix(1) + """ + for i in range(1, N + 1): + # extend matrix of all existing atom type by 1 + for a in atomTypes: + a.addToMatrix(1) - # create dummy atom and add it to list of atomTypes - numAtoms = len(atomTypes) - num = str(numAtoms + 1) - name = 'MAP' + num - val = '0.000000e-00' - matrix = [1 for j in range(numAtoms)] - matrix.append(1) - atomTypes.append(AtomType(num, name, val, val, val, val, val, val, matrix)) + # create dummy atom and add it to list of atomTypes + numAtoms = len(atomTypes) + num = str(numAtoms + 1) + name = "MAP" + num + val = "0.000000e-00" + matrix = [1 for j in range(numAtoms)] + matrix.append(1) + atomTypes.append(AtomType(num, name, val, val, val, val, val, val, matrix)) def check(atomTypes): - """ + """ - Parameters - ---------- - atomTypes + Parameters + ---------- + atomTypes - Returns - ------- + Returns + ------- - """ - N = len(atomTypes) - - for a in atomTypes: - if len(a.matrix) != N: - print(a) - sys.exit('Matrix with wrong size\n') + """ + N = len(atomTypes) + for a in atomTypes: + if len(a.matrix) != N: + print(a) + sys.exit("Matrix with wrong size\n") def writeOut(row1, row2, atomTypes, fileName, outName): - """ + """ - Parameters - ---------- - row1 - row2 - atomTypes - fileName - outName + Parameters + ---------- + row1 + row2 + atomTypes + fileName + outName - Returns - ------- + Returns + ------- - """ - rawLines = [] - N = len(atomTypes) + """ + rawLines = [] + N = len(atomTypes) - with open(fileName, 'r') as f: - rawLines = f.readlines() + with open(fileName, "r") as f: + rawLines = f.readlines() - lines = [raw.strip().split() for raw in rawLines] - - out = open(outName, 'w') - for i in range(0, row2): - if i <= row1: - writeLine(rawLines[i], out) - else: - if lines[i][0] == '#' or lines[i][0] == '#number': - if len(lines[i]) == 2: - if lines[i][1] == 'NRATT': - writeLine(rawLines[i], out) - out.write('{0:>10}\n'.format(N)) - else: - writeLine(rawLines[i], out) + lines = [raw.strip().split() for raw in rawLines] - writeAtomTypes(atomTypes, out) + out = open(outName, "w") + for i in range(0, row2): + if i <= row1: + writeLine(rawLines[i], out) + else: + if lines[i][0] == "#" or lines[i][0] == "#number": + if len(lines[i]) == 2: + if lines[i][1] == "NRATT": + writeLine(rawLines[i], out) + out.write("{0:>10}\n".format(N)) + else: + writeLine(rawLines[i], out) - for i in range(row2, len(lines)): - writeLine(rawLines[i], out) + writeAtomTypes(atomTypes, out) + for i in range(row2, len(lines)): + writeLine(rawLines[i], out) - out.close() + out.close() def writeLine(line, file): - """ + """ - Parameters - ---------- - line - file + Parameters + ---------- + line + file - Returns - ------- + Returns + ------- - """ - for item in line: - file.write_out_energy_trajs('%s' % item) + """ + for item in line: + file.write_out_energy_trajs("%s" % item) def writeAtomTypes(atomTypes, out): - """ - - Parameters - ---------- - atomTypes - out - - Returns - ------- + """ - """ - for a in atomTypes: - out.write_out_energy_trajs("{0:>9} {1:>7} {2:>14} {3:>14} {4:>13} {5:>13}\n" - .format(a.atomNum, a.atomName, a.sqrtC06, a.sqrtC12_1, a.sqrtC12_2, a.sqrtC12_3)) + Parameters + ---------- + atomTypes + out - out.write_out_energy_trajs('#CS6 CS12 parameters LJ14PAIR\n') - out.write_out_energy_trajs(" {0:<12} {1:>14}\n".format((a.sqrtC06NB).strip(), a.sqrtC12NB)) + Returns + ------- - matrix = a.matrix + """ + for a in atomTypes: + out.write_out_energy_trajs( + "{0:>9} {1:>7} {2:>14} {3:>14} {4:>13} {5:>13}\n".format( + a.atomNum, a.atomName, a.sqrtC06, a.sqrtC12_1, a.sqrtC12_2, a.sqrtC12_3 + ) + ) - for i in range(1, len(matrix) + 1): - if (i % 20 == 0 and i != 0): - out.write_out_energy_trajs(" %s\n" % matrix[i - 1]) - else: - out.write_out_energy_trajs(" %s" % matrix[i - 1]) + out.write_out_energy_trajs("#CS6 CS12 parameters LJ14PAIR\n") + out.write_out_energy_trajs(" {0:<12} {1:>14}\n".format((a.sqrtC06NB).strip(), a.sqrtC12NB)) - out.write_out_energy_trajs('\n#---\n') + matrix = a.matrix + for i in range(1, len(matrix) + 1): + if i % 20 == 0 and i != 0: + out.write_out_energy_trajs(" %s\n" % matrix[i - 1]) + else: + out.write_out_energy_trajs(" %s" % matrix[i - 1]) + out.write_out_energy_trajs("\n#---\n") -if __name__ == '__main__': - main() +if __name__ == "__main__": + main() diff --git a/pygromos/data/ff/atomType.py b/pygromos/data/ff/atomType.py index da1ab351..3380cfe5 100755 --- a/pygromos/data/ff/atomType.py +++ b/pygromos/data/ff/atomType.py @@ -1,43 +1,41 @@ class AtomType(object): - def __init__(self, atomNum, atomName, - sqrtC06, sqrtC12_1, sqrtC12_2, sqrtC12_3, - sqrtC06NB, sqrtC12NB, matrix): - """ + def __init__(self, atomNum, atomName, sqrtC06, sqrtC12_1, sqrtC12_2, sqrtC12_3, sqrtC06NB, sqrtC12NB, matrix): + """ - Parameters - ---------- - atomNum - atomName - sqrtC06 - sqrtC12_1 - sqrtC12_2 - sqrtC12_3 - sqrtC06NB - sqrtC12NB - matrix - """ - self.atomNum = atomNum - self.atomName = atomName - self.sqrtC06 = sqrtC06 - self.sqrtC12_1 = sqrtC12_1 - self.sqrtC12_2 = sqrtC12_2 - self.sqrtC12_3 = sqrtC12_3 - self.sqrtC06NB = sqrtC06NB - self.sqrtC12NB = sqrtC12NB - self.matrix = matrix + Parameters + ---------- + atomNum + atomName + sqrtC06 + sqrtC12_1 + sqrtC12_2 + sqrtC12_3 + sqrtC06NB + sqrtC12NB + matrix + """ + self.atomNum = atomNum + self.atomName = atomName + self.sqrtC06 = sqrtC06 + self.sqrtC12_1 = sqrtC12_1 + self.sqrtC12_2 = sqrtC12_2 + self.sqrtC12_3 = sqrtC12_3 + self.sqrtC06NB = sqrtC06NB + self.sqrtC12NB = sqrtC12NB + self.matrix = matrix - def __str__(self): - return '[' + self.atomNum + ' ' + self.atomName + ' ' + self.sqrtC06 + ' ' + self.sqrtC12_1 + ']' + def __str__(self): + return "[" + self.atomNum + " " + self.atomName + " " + self.sqrtC06 + " " + self.sqrtC12_1 + "]" - def addToMatrix(self, n): - """ + def addToMatrix(self, n): + """ - Parameters - ---------- - n + Parameters + ---------- + n - Returns - ------- + Returns + ------- - """ - self.matrix.append(n) \ No newline at end of file + """ + self.matrix.append(n) diff --git a/pygromos/data/gromos_compile_scripts/dstar/make_gromosXX.sh b/pygromos/data/gromos_compile_scripts/dstar/make_gromosXX.sh index 807739d0..9c00d955 100755 --- a/pygromos/data/gromos_compile_scripts/dstar/make_gromosXX.sh +++ b/pygromos/data/gromos_compile_scripts/dstar/make_gromosXX.sh @@ -6,4 +6,3 @@ cd $SRCPATH cd LINUX make -j8 make install # -d - diff --git a/pygromos/data/gromos_compile_scripts/dstar/premake_gromosXX.sh b/pygromos/data/gromos_compile_scripts/dstar/premake_gromosXX.sh index aaf7e4bf..5c7c09f3 100755 --- a/pygromos/data/gromos_compile_scripts/dstar/premake_gromosXX.sh +++ b/pygromos/data/gromos_compile_scripts/dstar/premake_gromosXX.sh @@ -21,4 +21,3 @@ CXX=${CXXFLAG} CC=${CCFLAG} #OPTIONS ../configure --disable-shared --enable-debug --with-gsl=/opt/dstar/progs/gcc-4.8.5/gsl-2.1/ --with-fftw=/opt/dstar/progs/gcc-4.8.5/fftw-3.3.4/ --disable-openmp --enable-mpi CXX=/opt/dstar/progs/gcc-4.8.5/openmpi-1.10.2/bin/mpiCC CC=/opt/dstar/progs/gcc-4.8.5/openmpi-1.10.2/bin/mpicc --prefix=${buildPATH} - diff --git a/pygromos/data/gromos_compile_scripts/euler/clean_gromosPP.sh b/pygromos/data/gromos_compile_scripts/euler/clean_gromosPP.sh index 33fdfc36..2e574015 100755 --- a/pygromos/data/gromos_compile_scripts/euler/clean_gromosPP.sh +++ b/pygromos/data/gromos_compile_scripts/euler/clean_gromosPP.sh @@ -4,6 +4,6 @@ buildPATH=you/want/gromos/here/build_gromosXX cd ${SRCPATH} rm LINUX/* -r -rmdir LINUX +rmdir LINUX rm ${buildPATH}/* -r rmdir ${buildPATH} diff --git a/pygromos/data/gromos_compile_scripts/euler/clean_gromosXX.sh b/pygromos/data/gromos_compile_scripts/euler/clean_gromosXX.sh index 71cecb94..ef21f058 100755 --- a/pygromos/data/gromos_compile_scripts/euler/clean_gromosXX.sh +++ b/pygromos/data/gromos_compile_scripts/euler/clean_gromosXX.sh @@ -3,7 +3,6 @@ GXXBUILDPATH=you/want/gromos/here/build_gromosXX cd ${GXXPATH} rm LINUX/* -r -rmdir LINUX +rmdir LINUX rm ${GXXBUILDPATH}/* -r rmdir ${GXXBUILDPATH} - diff --git a/pygromos/data/gromos_compile_scripts/euler/make_gromosPP.sh b/pygromos/data/gromos_compile_scripts/euler/make_gromosPP.sh index 3a7f28f8..19aa2d04 100755 --- a/pygromos/data/gromos_compile_scripts/euler/make_gromosPP.sh +++ b/pygromos/data/gromos_compile_scripts/euler/make_gromosPP.sh @@ -13,11 +13,11 @@ cd $PLSPATH cd LINUX make -j8 make install -~ -~ -~ -~ -~ -~ -~ -~ +~ +~ +~ +~ +~ +~ +~ +~ diff --git a/pygromos/data/gromos_compile_scripts/euler/make_gromosXX.sh b/pygromos/data/gromos_compile_scripts/euler/make_gromosXX.sh index f9fcb060..c9fd4b74 100755 --- a/pygromos/data/gromos_compile_scripts/euler/make_gromosXX.sh +++ b/pygromos/data/gromos_compile_scripts/euler/make_gromosXX.sh @@ -12,6 +12,5 @@ module load openblas/0.2.8_seq cd ${GXXPATH} mkdir LINUX cd LINUX -make -j8 +make -j8 make install - diff --git a/pygromos/data/gromos_compile_scripts/euler/premake_gromosXX.sh b/pygromos/data/gromos_compile_scripts/euler/premake_gromosXX.sh index c39463e5..69a6c1e3 100755 --- a/pygromos/data/gromos_compile_scripts/euler/premake_gromosXX.sh +++ b/pygromos/data/gromos_compile_scripts/euler/premake_gromosXX.sh @@ -12,7 +12,6 @@ module load openblas/0.2.8_seq #DO cd ${GXXPATH} mkdir LINUX -p -cd LINUX +cd LINUX ../configure --prefix=${BUILDXX} --disable-debug --enable-mpi --disable-openmp CXX=/cluster/apps/openmpi/1.6.5/x86_64/gcc_4.8.2/bin/mpiCC CC=/cluster/apps/openmpi/1.6.5/x86_64/gcc_4.8.2/bin/mpiCC - diff --git a/pygromos/data/simulation_parameters_templates/__init__.py b/pygromos/data/simulation_parameters_templates/__init__.py index 7184995e..c67d36bc 100644 --- a/pygromos/data/simulation_parameters_templates/__init__.py +++ b/pygromos/data/simulation_parameters_templates/__init__.py @@ -1,15 +1,14 @@ import os -imd_dir = os.path.dirname(__file__) - -template_emin = imd_dir+"/emin.imd" -template_emin_vac = imd_dir+"/vac_emin.imd" -template_md = imd_dir+"/md.imd" -template_md_tut = imd_dir+"/md_tut.imd" +imd_dir = os.path.dirname(__file__) -template_eds = imd_dir+"/eds_md.imd" -template_reeds = imd_dir+"/reeds_md.imd" -template_sd = imd_dir+"/vacuum_sd.imd" -template_hremd = imd_dir+"/hre_md.imd" +template_emin = imd_dir + "/emin.imd" +template_emin_vac = imd_dir + "/vac_emin.imd" +template_md = imd_dir + "/md.imd" +template_md_tut = imd_dir + "/md_tut.imd" +template_eds = imd_dir + "/eds_md.imd" +template_reeds = imd_dir + "/reeds_md.imd" +template_sd = imd_dir + "/vacuum_sd.imd" +template_hremd = imd_dir + "/hre_md.imd" diff --git a/pygromos/data/simulation_parameters_templates/emin.imd b/pygromos/data/simulation_parameters_templates/emin.imd index 3d4cd035..3382ea1c 100644 --- a/pygromos/data/simulation_parameters_templates/emin.imd +++ b/pygromos/data/simulation_parameters_templates/emin.imd @@ -3,65 +3,65 @@ TITLE END BOUNDCOND # NTB NDFMIN - 1 3 + 1 3 END CONSTRAINT # NTC - 3 + 3 # NTCP NTCP0(1) - 1 0.000100 + 1 0.000100 # NTCS NTCS0(1) - 1 0.000100 + 1 0.000100 END ENERGYMIN # NTEM NCYC DELE DX0 DXM NMIN FLIM - 1 0 0.1 0.01 0.05 2000 0.0 + 1 0 0.1 0.01 0.05 2000 0.0 END FORCE # BONDS ANGLES IMPROPER DIHEDRAL ELECTROSTATIC VDW - 1 1 1 1 1 1 + 1 1 1 1 1 1 # NEGR NRE - 3 1 2 3 + 3 1 2 3 END INITIALISE # NTIVEL NTISHK NTINHT NTINHB - 0 0 0 0 + 0 0 0 0 # NTISHI NTIRTC NTICOM - 1 0 0 + 1 0 0 # NTISTI - 0 + 0 # IG TEMPI - 210185 300.0 + 210185 300.0 END NONBONDED # NLRELE - 1 + 1 # APPAK RCRF EPSRF NSLFEXCL - 0.0 1.4 61 1 + 0.0 1.4 61 1 # NSHAPE ASHAPE NA2CLC TOLA2 EPSLS - -1 1.4 2 1e-10 0 + -1 1.4 2 1e-10 0 # NKX NKY NKZ KCUT - 10 10 10 100 + 10 10 10 100 # NGX NGY NGZ NASORD NFDORD NALIAS NSPORD - 32 32 32 3 2 3 4 + 32 32 32 3 2 3 4 # NQEVAL FACCUR NRDGRD NWRGRD - 100000 1.6 0 0 + 100000 1.6 0 0 # NLRLJ SLVDNS - 0 33.3 + 0 33.3 END PAIRLIST # ALGORITHM NSNB RCUTP RCUTL SIZE TYPE - 0 5 0.800000 1.400000 0.4 0 + 0 5 0.800000 1.400000 0.4 0 END PRINTOUT # NTPR NTPP - 300 0 + 300 0 END STEP # NSTLIM T DT - 3000 0.000000 0.002000 + 3000 0.000000 0.002000 END SYSTEM # NPM NSM - 1 930 + 1 930 END diff --git a/pygromos/data/simulation_parameters_templates/hre_md.imd b/pygromos/data/simulation_parameters_templates/hre_md.imd index 857d43e6..e3840175 100755 --- a/pygromos/data/simulation_parameters_templates/hre_md.imd +++ b/pygromos/data/simulation_parameters_templates/hre_md.imd @@ -15,7 +15,7 @@ REPLICA # NRET 1 # RET(1..NRET) - 300.0 + 300.0 # LRESCALE 1 # NRELAM @@ -165,4 +165,3 @@ WRITETRAJ # NTWX NTWSE NTWV NTWF NTWE NTWG NTWB 5000 0 0 0 20 0 0 END - diff --git a/pygromos/data/simulation_parameters_templates/md_tut.imd b/pygromos/data/simulation_parameters_templates/md_tut.imd index bccdfa49..4fab2cd5 100644 --- a/pygromos/data/simulation_parameters_templates/md_tut.imd +++ b/pygromos/data/simulation_parameters_templates/md_tut.imd @@ -3,29 +3,29 @@ TITLE END BOUNDCOND # NTB NDFMIN - 1 3 + 1 3 END COMTRANSROT # NSCM - 1000 + 1000 END CONSTRAINT # NTC - 3 + 3 # NTCP NTCP0(1) - 1 0.000100 + 1 0.000100 # NTCS NTCS0(1) - 1 0.000100 + 1 0.000100 END COVALENTFORM # NTBBH NTBAH NTBDN - 0 0 0 + 0 0 0 END FORCE # BONDS ANGLES IMPROPER DIHEDRAL ELECTROSTATIC VDW - 1 1 1 1 1 1 + 1 1 1 1 1 1 # NEGR NRE - 3 71 73 2863 + 3 71 73 2863 END INITIALISE # NTIVEL NTISHK NTINHT NTINHB @@ -33,7 +33,7 @@ INITIALISE # NTISHI NTIRTC NTICOM 1 0 1 # NTISTI - 0 + 0 # IG TEMPI 12416 300.0 END @@ -53,37 +53,37 @@ MULTIBATH END NONBONDED # NLRELE - 1 + 1 # APPAK RCRF EPSRF NSLFEXCL - 0.0 1.4 61 1 + 0.0 1.4 61 1 # NSHAPE ASHAPE NA2CLC TOLA2 EPSLS - 3 1.4 2 1e-10 0 + 3 1.4 2 1e-10 0 # NKX NKY NKZ KCUT - 10 10 10 100 + 10 10 10 100 # NGX NGY NGZ NASORD NFDORD NALIAS NSPORD - 32 32 32 3 2 3 4 + 32 32 32 3 2 3 4 # NQEVAL FACCUR NRDGRD NWRGRD - 100000 1.6 0 0 + 100000 1.6 0 0 # NLRLJ SLVDNS - 0 33.3 + 0 33.3 END PAIRLIST # ALGORITHM NSNB RCUTP RCUTL SIZE TYPE - 1 5 0.800000 1.400000 0.4 0 + 1 5 0.800000 1.400000 0.4 0 END PRESSURESCALE # COUPLE SCALE COMP TAUP VIRIAL - 2 1 0.000458 0.500000 2 + 2 1 0.000458 0.500000 2 # SEMIANISOTROPIC COUPLINGS(X, Y, Z) - 1 1 1 + 1 1 1 # PRES0(1...3,1...3) 0.06102 0 0 0 0.06102 0 - 0 0 0.06102 + 0 0 0.06102 END PRINTOUT # NTPR NTPP - 250 0 + 250 0 END STEP # NSTLIM T DT @@ -91,9 +91,9 @@ STEP END SYSTEM # NPM NSM - 1 5 + 1 5 END WRITETRAJ # NTWX NTWSE NTWV NTWF NTWE NTWG NTWB - 10 0 0 0 10 0 0 + 10 0 0 0 10 0 0 END diff --git a/pygromos/data/simulation_parameters_templates/reeds_md.imd b/pygromos/data/simulation_parameters_templates/reeds_md.imd index 54f3228e..4098576b 100755 --- a/pygromos/data/simulation_parameters_templates/reeds_md.imd +++ b/pygromos/data/simulation_parameters_templates/reeds_md.imd @@ -144,4 +144,3 @@ WRITETRAJ # NTWX NTWSE NTWV NTWF NTWE NTWG NTWB 5000 0 0 0 20 0 0 END - diff --git a/pygromos/data/simulation_parameters_templates/vac_emin.imd b/pygromos/data/simulation_parameters_templates/vac_emin.imd index 4f11cd1d..6d44231b 100644 --- a/pygromos/data/simulation_parameters_templates/vac_emin.imd +++ b/pygromos/data/simulation_parameters_templates/vac_emin.imd @@ -3,65 +3,65 @@ TITLE END BOUNDCOND # NTB NDFMIN - 0 0 + 0 0 END CONSTRAINT # NTC - 3 + 3 # NTCP NTCP0(1) - 1 0.000100 + 1 0.000100 # NTCS NTCS0(1) - 1 0.000100 + 1 0.000100 END ENERGYMIN # NTEM NCYC DELE DX0 DXM NMIN FLIM - 1 0 0.1 0.01 0.05 2000 0.0 + 1 0 0.1 0.01 0.05 2000 0.0 END FORCE # BONDS ANGLES IMPROPER DIHEDRAL ELECTROSTATIC VDW - 0 1 1 1 1 1 + 0 1 1 1 1 1 # NEGR NRE - 1 1 + 1 1 END INITIALISE # NTIVEL NTISHK NTINHT NTINHB - 0 0 0 0 + 0 0 0 0 # NTISHI NTIRTC NTICOM - 1 0 0 + 1 0 0 # NTISTI - 0 + 0 # IG TEMPI - 210185 300.0 + 210185 300.0 END NONBONDED # NLRELE - 1 + 1 # APPAK RCRF EPSRF NSLFEXCL - 0.0 1.4 61 1 + 0.0 1.4 61 1 # NSHAPE ASHAPE NA2CLC TOLA2 EPSLS - -1 1.4 2 1e-10 0 + -1 1.4 2 1e-10 0 # NKX NKY NKZ KCUT - 10 10 10 100 + 10 10 10 100 # NGX NGY NGZ NASORD NFDORD NALIAS NSPORD - 32 32 32 3 2 3 4 + 32 32 32 3 2 3 4 # NQEVAL FACCUR NRDGRD NWRGRD - 100000 1.6 0 0 + 100000 1.6 0 0 # NLRLJ SLVDNS - 0 33.3 + 0 33.3 END PAIRLIST # ALGORITHM NSNB RCUTP RCUTL SIZE TYPE - 0 5 0.800000 1.400000 0.4 0 + 0 5 0.800000 1.400000 0.4 0 END PRINTOUT # NTPR NTPP - 10 0 + 10 0 END STEP # NSTLIM T DT - 3000 0.000000 0.002000 + 3000 0.000000 0.002000 END SYSTEM # NPM NSM - 1 0 + 1 0 END diff --git a/pygromos/data/simulation_parameters_templates/vacuum_sd.imd b/pygromos/data/simulation_parameters_templates/vacuum_sd.imd index 946a5185..d7cdd3d7 100644 --- a/pygromos/data/simulation_parameters_templates/vacuum_sd.imd +++ b/pygromos/data/simulation_parameters_templates/vacuum_sd.imd @@ -71,4 +71,4 @@ END STOCHDYN # NTSD NTFR NSFR NBREF RCUTF CFRIC TEMPSD 1 1 100 5 0.3 91.0 298 -END \ No newline at end of file +END diff --git a/pygromos/data/solvent_coordinates/__init__.py b/pygromos/data/solvent_coordinates/__init__.py index cf8ec1fe..55ac4af8 100644 --- a/pygromos/data/solvent_coordinates/__init__.py +++ b/pygromos/data/solvent_coordinates/__init__.py @@ -1,3 +1,4 @@ import os + data_dir = os.path.dirname(__file__) -spc = data_dir+"/spc.cnf" +spc = data_dir + "/spc.cnf" diff --git a/pygromos/data/solvent_coordinates/ccl4.cnf b/pygromos/data/solvent_coordinates/ccl4.cnf index 135318cf..129f4fe0 100644 --- a/pygromos/data/solvent_coordinates/ccl4.cnf +++ b/pygromos/data/solvent_coordinates/ccl4.cnf @@ -1,7 +1,7 @@ TITLE 1000 CCL4 water molecules, cubic box, a = 5.426025513nm 5.5ns NPT (293K, 1atm), A.P. Kunz, 2010 -Ref: I.G. Tironi et al. 1996, Mol. Simulation 18:1 +Ref: I.G. Tironi et al. 1996, Mol. Simulation 18:1 END POSITION # first 24 chars ignored diff --git a/pygromos/data/solvent_coordinates/ch3oh.cnf b/pygromos/data/solvent_coordinates/ch3oh.cnf index 97022249..1725bb12 100644 --- a/pygromos/data/solvent_coordinates/ch3oh.cnf +++ b/pygromos/data/solvent_coordinates/ch3oh.cnf @@ -1,6 +1,6 @@ TITLE 1000 CH3OH molecules, cubic box, a = 4.066916770nm -2ns NPT (300K, 1atm), J. Dolenc, 2010 +2ns NPT (300K, 1atm), J. Dolenc, 2010 Ref: R. Walser et al. 2000, J. Chem. Phys. 112:10450 END POSITION diff --git a/pygromos/data/solvent_coordinates/chcl3.cnf b/pygromos/data/solvent_coordinates/chcl3.cnf index bd2bc397..add29c24 100644 --- a/pygromos/data/solvent_coordinates/chcl3.cnf +++ b/pygromos/data/solvent_coordinates/chcl3.cnf @@ -1,7 +1,7 @@ TITLE 1000 CHCL3 molecules, cubic box a = 5.081617402nm -3ns NPT (293K, 1atm), Z. Lin, 2009 -Ref: Z. Lin et al, 2010, Mol. Phys. 108:1749 +3ns NPT (293K, 1atm), Z. Lin, 2009 +Ref: Z. Lin et al, 2010, Mol. Phys. 108:1749 END POSITION # first 24 chars ignored diff --git a/pygromos/data/topology_templates/__init__.py b/pygromos/data/topology_templates/__init__.py index 72e181f6..32656ab3 100644 --- a/pygromos/data/topology_templates/__init__.py +++ b/pygromos/data/topology_templates/__init__.py @@ -3,5 +3,6 @@ """ import os + topology_template_dir = os.path.dirname(__file__) blank_topo_template = topology_template_dir + "/blank_template.top" diff --git a/pygromos/data/topology_templates/blank_serenity_template+spc.top b/pygromos/data/topology_templates/blank_serenity_template+spc.top index 05fc9cd9..f51c826c 100644 --- a/pygromos/data/topology_templates/blank_serenity_template+spc.top +++ b/pygromos/data/topology_templates/blank_serenity_template+spc.top @@ -75,4 +75,4 @@ SOLVENTCONSTR 1 3 0.1000000 2 3 0.1632990 END -# end of topology file \ No newline at end of file +# end of topology file diff --git a/pygromos/data/topology_templates/blank_template+spc.top b/pygromos/data/topology_templates/blank_template+spc.top index d91d9de6..b3de3730 100644 --- a/pygromos/data/topology_templates/blank_template+spc.top +++ b/pygromos/data/topology_templates/blank_template+spc.top @@ -68,4 +68,4 @@ SOLVENTCONSTR 1 3 0.1000000 2 3 0.1632990 END -# end of topology file \ No newline at end of file +# end of topology file diff --git a/pygromos/data/topology_templates/blank_template.top b/pygromos/data/topology_templates/blank_template.top index d91d9de6..b3de3730 100644 --- a/pygromos/data/topology_templates/blank_template.top +++ b/pygromos/data/topology_templates/blank_template.top @@ -68,4 +68,4 @@ SOLVENTCONSTR 1 3 0.1000000 2 3 0.1632990 END -# end of topology file \ No newline at end of file +# end of topology file diff --git a/pygromos/data/topology_templates/serenityff_template.top b/pygromos/data/topology_templates/serenityff_template.top index 2099cecb..09c1c2aa 100644 --- a/pygromos/data/topology_templates/serenityff_template.top +++ b/pygromos/data/topology_templates/serenityff_template.top @@ -377,4 +377,4 @@ SOLVENTCONSTR 1 3 0.1000000 2 3 0.1632990 END -# end of topology file \ No newline at end of file +# end of topology file diff --git a/pygromos/files/__init__.py b/pygromos/files/__init__.py index d6f9e8fd..f239a3e0 100644 --- a/pygromos/files/__init__.py +++ b/pygromos/files/__init__.py @@ -1,4 +1,4 @@ import os, sys + sys.path.append(os.path.dirname(__file__)) from pygromos.files import blocks - diff --git a/pygromos/files/_basics/_general_gromos_file.py b/pygromos/files/_basics/_general_gromos_file.py index f3edd7d9..ade29404 100644 --- a/pygromos/files/_basics/_general_gromos_file.py +++ b/pygromos/files/_basics/_general_gromos_file.py @@ -14,41 +14,42 @@ ##file class -class _general_gromos_file(): +class _general_gromos_file: """_general_gromos_file - This class is the generic gromos class, that takes care of all common gromos file featuers. + This class is the generic gromos class, that takes care of all common gromos file featuers. """ - _orig_file_path:str - path:str + + _orig_file_path: str + path: str _required_blocks = ["TITLE"] - _blocksset_names:List[str] + _blocksset_names: List[str] - _gromos_file_ending : str - #private - _blocks:Dict[str, blocks._generic_gromos_block] + _gromos_file_ending: str + # private + _blocks: Dict[str, blocks._generic_gromos_block] _block_order: List[str] = [] - _future_file : bool + _future_file: bool - def __init__(self, in_value:(str or dict or None or __class__), _future_file:bool=False): + def __init__(self, in_value: (str or dict or None or __class__), _future_file: bool = False): self._future_file = _future_file - if(isinstance(in_value, str)): + if isinstance(in_value, str): self.path = self._orig_file_path = in_value - if(self._future_file): + if self._future_file: pass - elif (os.path.exists(in_value)): + elif os.path.exists(in_value): self.read_blocks() else: raise IOError("Could not find File: ", in_value) - elif(isinstance(type(in_value), __class__)): + elif isinstance(type(in_value), __class__): raise NotImplementedError("This variant is not implemented") - elif(in_value is None): + elif in_value is None: self.path = None self._orig_file_path = None - #print("Empty class") + # print("Empty class") else: - raise ValueError("The given type of input could not be translated in "+str(__class__)+".__init__") - + raise ValueError("The given type of input could not be translated in " + str(__class__) + ".__init__") + def read_blocks(self): self._blocks = self.read_file() self._blocksset_names = list(self._blocks.keys()) @@ -57,15 +58,34 @@ def read_blocks(self): def __str__(self): ##first write out certain _blocks - out_text="" + out_text = "" for block in self._block_order: - if(block in self.get_block_names() and not isinstance(getattr(self, block,), type(None))): + if block in self.get_block_names() and not isinstance( + getattr( + self, + block, + ), + type(None), + ): out_text += getattr(self, block).block_to_string() ##write out rest of _blocks - rest_blocks = [block for block in self.get_block_names() if (not block in self._block_order and not isinstance(getattr(self, block,), type(None)))] + rest_blocks = [ + block + for block in self.get_block_names() + if ( + not block in self._block_order + and not isinstance( + getattr( + self, + block, + ), + type(None), + ) + ) + ] for block in rest_blocks: - if(block is None or getattr(self, block) is None): + if block is None or getattr(self, block) is None: continue else: out_text += getattr(self, block).block_to_string() @@ -82,10 +102,10 @@ def __getstate__(self): """ skip = [] attribute_dict = self.__dict__ - new_dict ={} + new_dict = {} for key in attribute_dict.keys(): - if (not isinstance(attribute_dict[key], Callable) and not key in skip): - new_dict.update({key:attribute_dict[key]}) + if not isinstance(attribute_dict[key], Callable) and not key in skip: + new_dict.update({key: attribute_dict[key]}) return new_dict @@ -93,7 +113,7 @@ def __setstate__(self, state): self.__dict__ = state def __deepcopy__(self, memo): - #print(self.__class__.__name__) + # print(self.__class__.__name__) copy_obj = self.__class__(in_value=None) copy_obj.__setstate__(copy.deepcopy(self.__getstate__())) return copy_obj @@ -113,12 +133,8 @@ def __eq__(self, __o: object) -> bool: return True else: return False - - - - - def get_block_names(self)->List[str]: + def get_block_names(self) -> List[str]: """get_block_names This is a function, that returns all _blocks, contained in an imd file. @@ -132,7 +148,13 @@ def get_block_names(self)->List[str]: return list(filter(lambda x: not x.startswith("_") and x.isupper(), vars(self).keys())) - def add_block(self, blocktitle:str=None, content:dict=None, block:blocks._generic_gromos_block=None, verbose:bool=False): + def add_block( + self, + blocktitle: str = None, + content: dict = None, + block: blocks._generic_gromos_block = None, + verbose: bool = False, + ): """add_block This method adds a gromos block to a gromos file object. @@ -152,16 +174,16 @@ def add_block(self, blocktitle:str=None, content:dict=None, block:blocks._generi None """ - if(block and not (blocktitle or content)): + if block and not (blocktitle or content): if verbose: print("import block from " + block.name) blocktitle = block.name - setattr(self, blocktitle, block) #modern way + setattr(self, blocktitle, block) # modern way - elif(blocktitle != None and content != None): - #if blocktitle in self._block_names: - if(isinstance(content, dict)): - if blocktitle == "TITLE": #TODO fIX IN PARSER + elif blocktitle != None and content != None: + # if blocktitle in self._block_names: + if isinstance(content, dict): + if blocktitle == "TITLE": # TODO fIX IN PARSER self.__setattr__(blocktitle, blocks.__getattribute__(blocktitle)(content)) else: try: @@ -174,26 +196,34 @@ def add_block(self, blocktitle:str=None, content:dict=None, block:blocks._generi from pygromos.files.topology.top import Top from pygromos.files.blocks import imd_blocks, topology_blocks - if(issubclass(self.__class__, Imd)): + if issubclass(self.__class__, Imd): self.kwCreateBlock(blocktitle, content, imd_blocks) - elif(issubclass(self.__class__, Top)): + elif issubclass(self.__class__, Top): self.kwCreateBlock(blocktitle, content, topology_blocks) else: self.kwCreateBlock(blocktitle, content, blocks) - + if verbose: print("++++++++++++++++++++++++++++++") print("New Block: Adding " + blocktitle + " block") print(content) except: - msg ="Error while adding new value - can not resolve value names in \'" + blocktitle + "\' block!\n" - msg += "Content is " + str(tuple(content.keys()))+"\n" - msg += "Block knows " + str((blocks.__getattribute__(blocktitle).__init__.__code__.co_varnames)[1:]) + "\n" + msg = ( + "Error while adding new value - can not resolve value names in '" + + blocktitle + + "' block!\n" + ) + msg += "Content is " + str(tuple(content.keys())) + "\n" + msg += ( + "Block knows " + + str((blocks.__getattribute__(blocktitle).__init__.__code__.co_varnames)[1:]) + + "\n" + ) raise IOError(msg) if verbose: - print("Block "+blocktitle+" added to gromos File object.") + print("Block " + blocktitle + " added to gromos File object.") - elif(isinstance(content, list)): + elif isinstance(content, list): block_class = blocks.__getattribute__(blocktitle) block = block_class(content) @@ -202,7 +232,7 @@ def add_block(self, blocktitle:str=None, content:dict=None, block:blocks._generi if verbose: print("++++++++++++++++++++++++++++++") print("New Block: Adding " + blocktitle + " block") - print(content) + print(content) else: raise Exception("Not implemented") @@ -223,21 +253,25 @@ def delete_block(self, blockName: str): delattr(self, blockName) def kwCreateBlock(self, blocktitle, content, blocks_lib): - block_type = blocks_lib.__getattribute__(blocktitle) #get the blocktype - sig = inspect.signature(block_type.__init__) #block init signature - known_params = list(sig.parameters.keys()) #the params the function knows - known_content = {k:v for k,v in content.items() if(k in known_params)} - unknown_content = {k:v for k,v in content.items() if(not k in known_params)} - - #construct class - self.__setattr__(blocktitle,block_type(**known_content)) - - if(len(unknown_content)>0): #add unkown parameters - warnings.warn("FOUND UNKOWN Parameters for "+str(block_type.__name__)+" adding these params: "+str(unknown_content)) + block_type = blocks_lib.__getattribute__(blocktitle) # get the blocktype + sig = inspect.signature(block_type.__init__) # block init signature + known_params = list(sig.parameters.keys()) # the params the function knows + known_content = {k: v for k, v in content.items() if (k in known_params)} + unknown_content = {k: v for k, v in content.items() if (not k in known_params)} + + # construct class + self.__setattr__(blocktitle, block_type(**known_content)) + + if len(unknown_content) > 0: # add unkown parameters + warnings.warn( + "FOUND UNKOWN Parameters for " + + str(block_type.__name__) + + " adding these params: " + + str(unknown_content) + ) [self.__getattribute__(blocktitle).__setattr__(k, v) for k, v in unknown_content.items()] - - def read_file(self)->Dict[str, any]: + def read_file(self) -> Dict[str, any]: """read_file give back the content. WARNING DEAPRECEATED. @@ -253,7 +287,7 @@ def read_file(self)->Dict[str, any]: print("Begin read in of file: " + self._orig_file_path) raise NotImplementedError("The read in parser function for general gromos files is not implemented yet!") - def write(self, out_path:str)->str: + def write(self, out_path: str) -> str: """write writes a general Gromos File out @@ -275,7 +309,7 @@ def write(self, out_path:str)->str: return out_path - def _write_to_file(self, out_path:str, content_str:str)->str: + def _write_to_file(self, out_path: str, content_str: str) -> str: """ write to file Returns @@ -283,8 +317,8 @@ def _write_to_file(self, out_path:str, content_str:str)->str: """ # 1) OpenFile - if (isinstance(out_path, str)): - if (os.path.exists(os.path.dirname(out_path))): + if isinstance(out_path, str): + if os.path.exists(os.path.dirname(out_path)): out_file = open(out_path, "w") else: raise IOError("Could not find directory to write to: " + str(os.path.dirname(out_path))) @@ -294,4 +328,4 @@ def _write_to_file(self, out_path:str, content_str:str)->str: # 3) Write File out_file.write(content_str) out_file.close() - return out_path \ No newline at end of file + return out_path diff --git a/pygromos/files/_basics/parser.py b/pygromos/files/_basics/parser.py index f966635a..eb860f59 100644 --- a/pygromos/files/_basics/parser.py +++ b/pygromos/files/_basics/parser.py @@ -16,19 +16,20 @@ import re -#translation dicts +# translation dicts imd_field_translation_dict = { - "FORCE": {"BONDS": ["bonds"], - "ANGLES": ["angles"], - "IMPROPER": ["imp.", "improper"], - "DIHEDRAL": ["dihe", "dihedral"], - "ELECTROSTATIC": ["charge", "electrostatic"], - "VDW": ["nonbonded", "vdW"] - }, + "FORCE": { + "BONDS": ["bonds"], + "ANGLES": ["angles"], + "IMPROPER": ["imp.", "improper"], + "DIHEDRAL": ["dihe", "dihedral"], + "ELECTROSTATIC": ["charge", "electrostatic"], + "VDW": ["nonbonded", "vdW"], + }, "PAIRLIST": {"ALGORITHM": ["algorithm"]}, } -#private functions +# private functions def _gather_bracket_key(keys: List[str]) -> List[str]: """_gather_bracket_key private @@ -62,7 +63,7 @@ def _gather_bracket_key(keys: List[str]) -> List[str]: collect.append(x) key_bracket = " ".join(collect) - if (tmp_key): + if tmp_key: key_bracket = "".join(tmp_key + key_bracket) gathered_keys.append(key_bracket) collect = [] @@ -72,10 +73,10 @@ def _gather_bracket_key(keys: List[str]) -> List[str]: gathered_keys.append(x) return gathered_keys except IndexError as err: - print("Index Error - While gathering bracket, unknown key: \""+str(x)+"\" ("+str(err)+")") + print('Index Error - While gathering bracket, unknown key: "' + str(x) + '" (' + str(err) + ")") -def _update_line_information(subkeys:List[str], values:List[any], sub_content:Dict[str, any]): +def _update_line_information(subkeys: List[str], values: List[any], sub_content: Dict[str, any]): """_update_line_information private Subfunction of read_gromos_top - read a gromos block - read update_line_information: @@ -106,7 +107,7 @@ def _update_line_information(subkeys:List[str], values:List[any], sub_content:Di sub_content.update({" ".join(subkeys): values}) -def _read_gromos_subblock(block:List[str])->Dict[str, any]: +def _read_gromos_subblock(block: List[str]) -> Dict[str, any]: """Subfunction of read_gromos_imd private read a gromos block @@ -133,7 +134,7 @@ def _read_gromos_subblock(block:List[str])->Dict[str, any]: if line.strip().startswith("#"): temp = line.lstrip("#").strip() if not temp.isdigit(): - #print("Is NOT number: ",temp,"<") + # print("Is NOT number: ",temp,"<") if not first_key: _update_line_information(subkeys=subkeys, values=values, sub_content=sub_content) subkeys = line.replace("#", "").split() @@ -144,7 +145,7 @@ def _read_gromos_subblock(block:List[str])->Dict[str, any]: elif not first_key: # no fields? tmp_values = line.split() - if (len(tmp_values) > 0): # collect all values + if len(tmp_values) > 0: # collect all values if first_value: values = tmp_values first_value = False @@ -165,7 +166,7 @@ def _read_gromos_subblock(block:List[str])->Dict[str, any]: return sub_content -def _read_gromos_block(lines:List[str])->Dict[str, str]: +def _read_gromos_block(lines: List[str]) -> Dict[str, str]: """_read_gromos_block private seperate gromos plocks into a dictionary @@ -180,16 +181,16 @@ def _read_gromos_block(lines:List[str])->Dict[str, str]: Dict[str, str] contains all blocks and the block contents """ - first_key=True + first_key = True blocks = {} - key="" + key = "" block_lines = [] for line in lines: - if(first_key and not line.startswith("#")): + if first_key and not line.startswith("#"): key = line.strip() first_key = False - elif(line.strip().startswith("END")): + elif line.strip().startswith("END"): blocks.update({key: block_lines}) first_key = True block_lines = [] @@ -198,18 +199,18 @@ def _read_gromos_block(lines:List[str])->Dict[str, str]: return blocks -#FUNCTION - parser -def read_general_gromos_file(path:str)->Dict: +# FUNCTION - parser +def read_general_gromos_file(path: str) -> Dict: data = {} first_key = True key = "" block = [] - with open(path, 'r') as infile: + with open(path, "r") as infile: for line in infile: if first_key: - if(line.startswith("#")): + if line.startswith("#"): continue key = line.strip().upper() first_key = False @@ -224,7 +225,7 @@ def read_general_gromos_file(path:str)->Dict: ## TOP -def read_disres(in_path:str)->Dict: +def read_disres(in_path: str) -> Dict: """read_disres This function can read distance restraints @@ -236,31 +237,34 @@ def read_disres(in_path:str)->Dict: ------- Dict """ - #specific parser for subblocks of disres files + # specific parser for subblocks of disres files def _read_disres_subblock(blocks): result_data = {} for block in blocks: - if (block == "TITLE"): + if block == "TITLE": block_obj = getattr(tb, block)(content=blocks[block]) result_data.update({block: block_obj}) - elif(block == "DISTANCERESSPEC"): + elif block == "DISTANCERESSPEC": block_obj = getattr(tb, block)(content=blocks[block]) result_data.update({block: block_obj}) else: - raise IOError("DISRES parser does not know block: "+str(block)+"\n with content: "+"\n".join(blocks[block])) + raise IOError( + "DISRES parser does not know block: " + str(block) + "\n with content: " + "\n".join(blocks[block]) + ) return result_data with open(in_path, "r") as infile: lines = infile.readlines() - #parse the coarse gromos_block structure + # parse the coarse gromos_block structure blocks = _read_gromos_block(lines) - #parse data of the _blocks + # parse data of the _blocks data = _read_disres_subblock(blocks) return data -def read_ptp(in_path:str)->Dict: + +def read_ptp(in_path: str) -> Dict: """read_disres This function can read distance restraints @@ -272,27 +276,30 @@ def read_ptp(in_path:str)->Dict: ------- Dict """ - #specific parser for subblocks of disres files - def _read_ptp_subblock(blocks): + # specific parser for subblocks of disres files + def _read_ptp_subblock(blocks): result_data = {} for block in blocks: - if (hasattr(pb, block)): - atom_block = getattr(pb, block)(content= blocks[block]) + if hasattr(pb, block): + atom_block = getattr(pb, block)(content=blocks[block]) result_data.update({block: atom_block}) else: - raise IOError("PTP parser does not know block: "+str(block)+"\n with content: "+"\n".join(blocks[block])) + raise IOError( + "PTP parser does not know block: " + str(block) + "\n with content: " + "\n".join(blocks[block]) + ) return result_data with open(in_path, "r") as infile: lines = infile.readlines() - #parse the coarse gromos_block structure + # parse the coarse gromos_block structure blocks = _read_gromos_block(lines) - #parse data of the _blocks + # parse data of the _blocks data = _read_ptp_subblock(blocks) return data + ##COORDS -def read_cnf(in_file_path:str, verbose:bool=False)->Dict[str, str]: +def read_cnf(in_file_path: str, verbose: bool = False) -> Dict[str, str]: """read_cnf This function is reading in cnf files from gromos and translates them to a dict if possible. atomP = namedtuple("AtomP", "resID resName atomType atomID xp yp zp") @@ -311,42 +318,55 @@ def read_cnf(in_file_path:str, verbose:bool=False)->Dict[str, str]: """ - known_blocks = {"TITLE", "TIMESTEP", "POSITION", "LATTICESHIFTS", "VELOCITY", "POSRESSPEC", "REFPOSITION", "GENBOX", - "PERTDATA", "STOCHINT"} + known_blocks = { + "TITLE", + "TIMESTEP", + "POSITION", + "LATTICESHIFTS", + "VELOCITY", + "POSRESSPEC", + "REFPOSITION", + "GENBOX", + "PERTDATA", + "STOCHINT", + } file = open(in_file_path, "r") data = {} - first_key=False + first_key = False block = "none" subblock = [] - #Translate string + # Translate string for line in file.readlines(): - if (not first_key and not "\#" in line and len(line.split()) == 1): - first_key =True + if not first_key and not "\#" in line and len(line.split()) == 1: + first_key = True block = line.strip().split()[0] - elif("END" == line.strip()): - if(block in known_blocks): + elif "END" == line.strip(): + if block in known_blocks: atom_block = getattr(blocks.coords, block)(content=subblock) data.update({block: atom_block}) else: print("WARNING!: Don't know block: " + block + ". read it simple.") data.update({block: _generic_gromos_block(name=block, used=True, content=subblock)}) - first_key=False + first_key = False block = "none" subblock = [] - elif(block == "none" ): - if(line.startswith("#")): + elif block == "none": + if line.startswith("#"): continue else: - raise IOError("coord file has inconsistent gromos Block structure!\n This line is out of block: \n"+line) + raise IOError( + "coord file has inconsistent gromos Block structure!\n This line is out of block: \n" + line + ) else: - if(not "#" in line): + if not "#" in line: subblock.append(line) return data + ##REEDS -def read_repdat(path: str, Vj_header=False) ->(Dict, List[blocks.repdat.replica_stat]): +def read_repdat(path: str, Vj_header=False) -> (Dict, List[blocks.repdat.replica_stat]): """ Careful old description! Parameters @@ -361,127 +381,148 @@ def read_repdat(path: str, Vj_header=False) ->(Dict, List[blocks.repdat.replica file = open(path, "r") - system_options={} - data_header=[] - data_values=[] - data_values_start=False + system_options = {} + data_header = [] + data_values = [] + data_values_start = False - first=True - new_repdat=False + first = True + new_repdat = False for line in file.readlines(): - if(first and "#======================" in line): - #HACK! TODO: make this hackless... currently due to the multiple gromos verions needed. + if first and "#======================" in line: + # HACK! TODO: make this hackless... currently due to the multiple gromos verions needed. new_repdat = True break - first =False - if(line.startswith("#")): - if(Vj_header): - data_header = list(map(lambda x: x.split("(")[0], filter(lambda x: not str(x).startswith("Vj"), line.replace("#", "").split()))) + first = False + if line.startswith("#"): + if Vj_header: + data_header = list( + map( + lambda x: x.split("(")[0], + filter(lambda x: not str(x).startswith("Vj"), line.replace("#", "").split()), + ) + ) else: data_header = list(line.replace("#", "")) data_values_start = True - elif(data_values_start): + elif data_values_start: data_values.append(line.split()) else: - if(line.strip().startswith("E")): + if line.strip().startswith("E"): fields = line.split() fields = [fields[0], fields[1:]] else: fields = line.strip().split("\t") - if(len(fields)>1): - key = fields[0].replace(":","").strip().replace("Number of ", "").replace(" ", "_").replace(",_num", "_").replace("=","").replace("_(RE-EDS)", "") + if len(fields) > 1: + key = ( + fields[0] + .replace(":", "") + .strip() + .replace("Number of ", "") + .replace(" ", "_") + .replace(",_num", "_") + .replace("=", "") + .replace("_(RE-EDS)", "") + ) value = fields[1] - system_options.update({key:value}) + system_options.update({key: value}) - if(new_repdat): ### TODO: NEW PARSER for actual gromos version! + if new_repdat: ### TODO: NEW PARSER for actual gromos version! file.close() eir = {} system_options_dict = {} eir_ind = 1 - with open(path, 'r') as repdat: - header = takewhile(lambda s: s.startswith('#'), repdat) + with open(path, "r") as repdat: + header = takewhile(lambda s: s.startswith("#"), repdat) for line in header: - fields = line.replace('(RE-EDS)',"").replace("#", "").split() - if(len(fields)>1): - if(fields[0] == "T"): + fields = line.replace("(RE-EDS)", "").replace("#", "").split() + if len(fields) > 1: + if fields[0] == "T": system_options_dict.update({"T": float(fields[1])}) - elif(fields[0] == "s"): + elif fields[0] == "s": system_options_dict.update({"s": list(map(float, fields[1:]))}) - elif("eir" in fields[0] or re.search("E[0-9]*R\(s\)", fields[0])): - if("eir" in fields[0]): + elif "eir" in fields[0] or re.search("E[0-9]*R\(s\)", fields[0]): + if "eir" in fields[0]: eir.update({eir_ind: list(map(float, fields[7:]))}) else: eir.update({eir_ind: list(map(float, fields[1:]))}) eir_ind += 1 system_options_dict.update({"state_eir": eir}) - system_options = blocks.repdat.repex_system(s=system_options_dict["s"], T=system_options_dict["T"], state_eir=system_options_dict["state_eir"]) + system_options = blocks.repdat.repex_system( + s=system_options_dict["s"], T=system_options_dict["T"], state_eir=system_options_dict["state_eir"] + ) - #read in data + # read in data df = pd.read_csv(path, comment="#", delim_whitespace=True) - #To do: messy juggling to match old fun + # To do: messy juggling to match old fun df.rename(columns={"exch": "s"}, inplace=True) - #orig column order- to be maintained, just replace V columns by state_potential dict + # orig column order- to be maintained, just replace V columns by state_potential dict data_header = df.columns V_cols = [col for col in df.columns if (col.startswith("V"))] rest_cols = [col for col in df.columns if (col not in V_cols)] state_potential = list(df[V_cols].T.to_dict().values()) - dict_list= list(df[rest_cols].T.to_dict().values()) + dict_list = list(df[rest_cols].T.to_dict().values()) [dict_vals.update({"state_potentials": state_V}) for state_V, dict_vals in zip(state_potential, dict_list)] - new_header = [x for x in data_header if(not x.startswith("V"))]+["state_potentials"] + new_header = [x for x in data_header if (not x.startswith("V"))] + ["state_potentials"] df = pd.DataFrame(dict_list) df = df[new_header] - df = df.astype({'ID': 'int32', 'partner': 'int32', 'run': 'int32','s': 'int32'}) + df = df.astype({"ID": "int32", "partner": "int32", "run": "int32", "s": "int32"}) return system_options, df - + else: - #cleanup system_options - new_dict = {i: system_options[i] for i in system_options if not (i.startswith("eir") or i.strip().startswith("E")) and (i == "s" or i == "T")} - #print(new_dict.keys()) - if("T" in new_dict): + # cleanup system_options + new_dict = { + i: system_options[i] + for i in system_options + if not (i.startswith("eir") or i.strip().startswith("E")) and (i == "s" or i == "T") + } + # print(new_dict.keys()) + if "T" in new_dict: new_dict.update({"T": float(new_dict["T"])}) - if("s" in new_dict): + if "s" in new_dict: new_dict.update({"s": list(map(float, new_dict["s"].split()))}) - if("lambda" in new_dict): + if "lambda" in new_dict: new_dict.update({"s": list(map(float, new_dict["lambda"].split()))}) - eir= {} - eir_state=1 + eir = {} + eir_state = 1 for i in system_options: - if(i.startswith("eir")): + if i.startswith("eir"): eir.update({eir_state: list(map(float, system_options[i].split()))}) eir_state += 1 - elif(i.strip().startswith("E"+str(eir_state)+"R")): + elif i.strip().startswith("E" + str(eir_state) + "R"): eir.update({eir_state: list(map(float, system_options[i]))}) eir_state += 1 - new_dict.update({"state_eir":eir}) + new_dict.update({"state_eir": eir}) system_options = blocks.repdat.repex_system(s=new_dict["s"], T=new_dict["T"], state_eir=new_dict["state_eir"]) - #data - #clean up data + # data + # clean up data head_num = len(data_header) values = [] for line in data_values: - pots = {data_header[i]: float(line[i]) for i in range(head_num) if(data_header[i].startswith("V"))} + pots = {data_header[i]: float(line[i]) for i in range(head_num) if (data_header[i].startswith("V"))} value = {data_header[i]: float(line[i]) for i in range(head_num) if not (data_header[i].startswith("V"))} value.update({"state_potentials": pots}) values.append(value) - new_header = [x for x in data_header if(not x.startswith("V"))]+["state_potentials"] + new_header = [x for x in data_header if (not x.startswith("V"))] + ["state_potentials"] df = pd.DataFrame(values) df = df[new_header] return system_options, df + ##IMD -def read_imd(in_file_path:str)->Dict: +def read_imd(in_file_path: str) -> Dict: """imd parser Parameters @@ -495,30 +536,30 @@ def read_imd(in_file_path:str)->Dict: dict - containing all _blocks as keys and possible fields as subkeys """ - def translate_subcontent_keys(key:str, sub_content:dict, translation_dict:dict)->dict: - if(key in translation_dict): - #print(key) - #print(list(sub_content)) - #print(translation_dict[key]) + def translate_subcontent_keys(key: str, sub_content: dict, translation_dict: dict) -> dict: + if key in translation_dict: + # print(key) + # print(list(sub_content)) + # print(translation_dict[key]) translated_sub_content = {} sub_trans_dict = translation_dict[key] - for sub_key in sub_content: #assign new standardized keys fot the block fields + for sub_key in sub_content: # assign new standardized keys fot the block fields tmp_sub_key = None for x in sub_trans_dict: - if(sub_key in sub_trans_dict[x]): + if sub_key in sub_trans_dict[x]: tmp_sub_key = x break - if(tmp_sub_key != None): - #print("replace: "+sub_key+" with "+tmp_sub_key) - translated_sub_content.update({tmp_sub_key : sub_content[sub_key]}) + if tmp_sub_key != None: + # print("replace: "+sub_key+" with "+tmp_sub_key) + translated_sub_content.update({tmp_sub_key: sub_content[sub_key]}) else: - #print("skipping: "+sub_key) + # print("skipping: "+sub_key) translated_sub_content.update({sub_key: sub_content[sub_key]}) return translated_sub_content else: return sub_content - def read_gromos_imd_block(block)->dict: + def read_gromos_imd_block(block) -> dict: """read_gromos_imd_block Subfunction of read_gromos_imd - read a gromos block: @@ -541,7 +582,7 @@ def read_gromos_imd_block(block)->dict: for line in block: if line.strip().startswith("#"): # comment line defining field => keys for fields - if not first_key and len(values) >0: + if not first_key and len(values) > 0: update_line_information(subkeys=subkeys, values=values, sub_content=sub_content) subkeys = line.replace("#", "").split() values = [] @@ -551,7 +592,7 @@ def read_gromos_imd_block(block)->dict: elif not first_key: # no fields? tmp_values = line.split() - if (len(tmp_values) > 0): #collect all values + if len(tmp_values) > 0: # collect all values if first_value: values = tmp_values first_value = False @@ -560,7 +601,7 @@ def read_gromos_imd_block(block)->dict: extend_first = False else: values.append(tmp_values) - #print("TEST "+str(tmp_values)) + # print("TEST "+str(tmp_values)) else: values.append(line) first_value = False @@ -593,7 +634,7 @@ def update_line_information(subkeys, values, sub_content: dict): # call by ref check how comment keys fit to data try: - if len(subkeys) == len(values) and len(subkeys) > 1: #more keys and equally ammount of values + if len(subkeys) == len(values) and len(subkeys) > 1: # more keys and equally ammount of values # Hack MULTIBATH block if "TEMP0" in subkeys[0]: if isinstance(values[0], list): @@ -611,20 +652,20 @@ def update_line_information(subkeys, values, sub_content: dict): else: sub_content.update({key: values[ind] for ind, key in enumerate(subkeys)}) - elif len(subkeys) == 1 and len(values) == 1:#1 keys and 1 value todo: really needed??? bschroed + elif len(subkeys) == 1 and len(values) == 1: # 1 keys and 1 value todo: really needed??? bschroed sub_content.update({subkeys[0]: values[0]}) - elif len(subkeys) == 1 and len(values) > 1: #1 key and more values + elif len(subkeys) == 1 and len(values) > 1: # 1 key and more values sub_content.update({subkeys[0]: values}) - elif len(values) == 1: #more keys and 1 value + elif len(values) == 1: # more keys and 1 value sub_content.update({" ".join(subkeys): values[0]}) - elif len(values) > 0: #unrecognizable LINE! - more values than keys and more than one key - #if("..." in subkeys): + elif len(values) > 0: # unrecognizable LINE! - more values than keys and more than one key + # if("..." in subkeys): # make_keys=len(values)-2 # tmp_subkeys=[subkeys[0]]+[subkeys[1].replace("1", "").replace("(", "").replace(")","")+"_"+str(i) for i in range(make_keys) ]+ [subkeys[len(subkeys)-1].replace("(", "_").replace(")","")] # sub_content.update({co: values[ind] for ind,co in enumerate(tmp_subkeys)}) - if(len(values)%len(subkeys) == 0): #possible matrix as content? - n_vals=int(len(values)/len(subkeys)) + if len(values) % len(subkeys) == 0: # possible matrix as content? + n_vals = int(len(values) / len(subkeys)) # Hack MULTIBATH block if "LAST" in subkeys[0]: if isinstance(values[0], list): @@ -634,16 +675,18 @@ def update_line_information(subkeys, values, sub_content: dict): sub_content.update({subkeys[2]: values[2::3]}) else: for ind, subkey in enumerate(subkeys): - start= ind*n_vals - end=start+n_vals + start = ind * n_vals + end = start + n_vals sub_content.update({subkey: values[start:end]}) # Hack PRESSURE block - SEMIANISOTROPIC has three parameters per parametername elif str(subkeys[0]) == "SEMIANISOTROPIC": sub_content.update({subkeys[0]: values}) # Hack FORCE block - energy groups do not have a parameter name per parameter elif str(subkeys[0]) == "NEGR": - if not ((len(values)-1) == int((values[0]))): - print("Warning - In FORCE block: Number of energy groups does not match number of last atoms given!") + if not ((len(values) - 1) == int((values[0]))): + print( + "Warning - In FORCE block: Number of energy groups does not match number of last atoms given!" + ) sub_content.update({subkeys[0]: values[0], "NRE": values[1:]}) # Hack INNERLOOP block - four parameter names but only 3 parameters (NDEVG not implemented) elif str(subkeys[0]) == "NTILM": @@ -672,11 +715,11 @@ def update_line_information(subkeys, values, sub_content: dict): sub_content.update({" ".join(subkeys): values}) except: print("Errors while reading imd-file.") - #TypeError: - #if subkeys is None: - # print("Empty comment line found! Line ignored.") - #else: - # print("Unknown TypeError.") + # TypeError: + # if subkeys is None: + # print("Empty comment line found! Line ignored.") + # else: + # print("Unknown TypeError.") data = {} @@ -684,20 +727,22 @@ def update_line_information(subkeys, values, sub_content: dict): key = "" block = [] - with open(in_file_path, 'r') as infile: + with open(in_file_path, "r") as infile: for line in infile: if first_key: - if(line.startswith("#")): + if line.startswith("#"): continue key = line.strip().upper() first_key = False elif "END" in line: - #print(key) - #print(block) + # print(key) + # print(block) sub_content = read_gromos_imd_block(block=block) - #print(sub_content) - sub_content = translate_subcontent_keys(key=key, sub_content=sub_content, translation_dict=imd_field_translation_dict) - #print(sub_content) + # print(sub_content) + sub_content = translate_subcontent_keys( + key=key, sub_content=sub_content, translation_dict=imd_field_translation_dict + ) + # print(sub_content) data.update({key: sub_content}) block = [] first_key = True @@ -706,8 +751,9 @@ def update_line_information(subkeys, values, sub_content: dict): infile.close() return data + ##SIMPLIFIED Pasers- CRUDE - not necessarily correct -def read_simple_trx(in_file_path:str, every_step:int=1, verbose:bool=True)->Dict: +def read_simple_trx(in_file_path: str, every_step: int = 1, verbose: bool = True) -> Dict: """ Needs output for checknig. Simple tre_ read - reads only _blocks! does not seperate fields. @@ -722,48 +768,48 @@ def read_simple_trx(in_file_path:str, every_step:int=1, verbose:bool=True)->Dict dict - containing all _blocks as keys (Title, Eneversion, num_trials {1:{}, 2:{} ....}) """ - data = {"TIMESTEP":{}} + data = {"TIMESTEP": {}} key = "" block = [] subblock = {} - timestep=0 + timestep = 0 first_key = True - issubblock=False - firstTitleBlock=True - firstEneVersionBlock=True + issubblock = False + firstTitleBlock = True + firstEneVersionBlock = True skip = False - with open(in_file_path, 'r') as infile: + with open(in_file_path, "r") as infile: current_step = 0 skip_frame = False - step_filter = lambda step_number: step_number == 0 or step_number%every_step == 0 + step_filter = lambda step_number: step_number == 0 or step_number % every_step == 0 for line in infile: - if first_key: #BlockHeader - #Keep only one Title - if("TITLE" in line and not firstTitleBlock ): - skip=True + if first_key: # BlockHeader + # Keep only one Title + if "TITLE" in line and not firstTitleBlock: + skip = True - #Keep only one eneversion - elif("ENEVERSION" in line and not firstEneVersionBlock): - skip =True + # Keep only one eneversion + elif "ENEVERSION" in line and not firstEneVersionBlock: + skip = True - elif ("TIMESTEP" in line and step_filter(current_step)): - if(timestep != 0): + elif "TIMESTEP" in line and step_filter(current_step): + if timestep != 0: data["TIMESTEP"][timestep].update(subblock) subblock = {} - timestep +=1 + timestep += 1 vals = next(infile).split() - data["TIMESTEP"].update({timestep :{"steps": int(vals[0]), "time": float(vals[1])}}) + data["TIMESTEP"].update({timestep: {"steps": int(vals[0]), "time": float(vals[1])}}) skip = True - elif ("TITLE" in line): + elif "TITLE" in line: key = line.strip() firstTitleBlock = False - elif ("ENEVERSION" in line): + elif "ENEVERSION" in line: key = line.strip() firstEneVersionBlock = False @@ -772,7 +818,7 @@ def read_simple_trx(in_file_path:str, every_step:int=1, verbose:bool=True)->Dict key = line.strip() first_key = False - #BlockEnds + # BlockEnds elif "END" in line and issubblock: subblock.update({key: block}) block = [] @@ -789,10 +835,11 @@ def read_simple_trx(in_file_path:str, every_step:int=1, verbose:bool=True)->Dict data.update({key: block}) block = [] first_key = True - if(key == "TIMESTEP"): current_step +=1 + if key == "TIMESTEP": + current_step += 1 continue - #Contentlines + # Contentlines elif skip: continue @@ -800,29 +847,30 @@ def read_simple_trx(in_file_path:str, every_step:int=1, verbose:bool=True)->Dict block.append(line) continue - if(not first_key): + if not first_key: raise IOError("The Final gromos Block was not terminated!") - #lastBlock - if (timestep != 0): + # lastBlock + if timestep != 0: data["TIMESTEP"][timestep].update(subblock) infile.close() return data + def read_tre(in_file_path: str, every_step: int = 1, verbose: bool = True) -> Dict: """ - Needs output for checknig. - Simple tre_ read - reads only _blocks! does not seperate fields. - rather ugly! but not much time! - Parameters - ---------- - in_file_path : str - - Returns - ------- - Dict - dict - containing all _blocks as keys (Title, Eneversion, num_trials {1:{}, 2:{} ....}) - """ + Needs output for checknig. + Simple tre_ read - reads only _blocks! does not seperate fields. + rather ugly! but not much time! + Parameters + ---------- + in_file_path : str + + Returns + ------- + Dict + dict - containing all _blocks as keys (Title, Eneversion, num_trials {1:{}, 2:{} ....}) + """ data = {"TIMESTEP": {}} @@ -831,7 +879,7 @@ def read_tre(in_file_path: str, every_step: int = 1, verbose: bool = True) -> Di block = [] frameSubBlocks = {} - #control bools + # control bools isBlockTitle = True isFrameSubBlock = False isFirstTitleBlock = True @@ -840,35 +888,35 @@ def read_tre(in_file_path: str, every_step: int = 1, verbose: bool = True) -> Di skipFrame = False doKeepFrameData = lambda step_number: step_number == 0 or step_number % every_step == 0 - with open(in_file_path, 'r') as infile: + with open(in_file_path, "r") as infile: for line in infile: if isBlockTitle: # BlockHeader line = line.strip() - if ("TITLE" in line): - if (isFirstTitleBlock): # only keep one title block + if "TITLE" in line: + if isFirstTitleBlock: # only keep one title block key = line.strip() isFirstTitleBlock = False else: skipBlockLines = True - elif ("ENEVERSION" in line): - if (isFirstEneVersionBlock): # only keep one title block + elif "ENEVERSION" in line: + if isFirstEneVersionBlock: # only keep one title block key = line.strip() isFirstEneVersionBlock = False else: skipBlockLines = True - elif ("TIMESTEP" in line): - if (doKeepFrameData(timestep)): # store data starts with - if(timestep != 0 ): + elif "TIMESTEP" in line: + if doKeepFrameData(timestep): # store data starts with + if timestep != 0: data["TIMESTEP"].update(frameSubBlocks) timestep += 1 vals = next(infile).split() frameSubBlocks = {timestep: {"steps": int(vals[0]), "time": float(vals[1])}} - skipFrame=False + skipFrame = False else: timestep += 1 - skipFrame=True + skipFrame = True skipBlockLines = True - elif ("ENERGY03" in line or "VOLUMEPRESSURE03" in line): # Known TRC subblocks + elif "ENERGY03" in line or "VOLUMEPRESSURE03" in line: # Known TRC subblocks isFrameSubBlock = True key = line.strip() else: @@ -894,29 +942,30 @@ def read_tre(in_file_path: str, every_step: int = 1, verbose: bool = True) -> Di block.append(line) continue - if (not isBlockTitle): + if not isBlockTitle: raise IOError("The Final gromos Block was not terminated by an END!") # lastBlock - if (timestep != 0 and len(frameSubBlocks) > 0): + if timestep != 0 and len(frameSubBlocks) > 0: data["TIMESTEP"].update(frameSubBlocks) return data -def read_trc(in_file_path:str, every_step:int=1, verbose:bool=True)->Dict: + +def read_trc(in_file_path: str, every_step: int = 1, verbose: bool = True) -> Dict: + """ + Needs output for checknig. + Simple tre_ read - reads only _blocks! does not seperate fields. + rather ugly! but not much time! + Parameters + ---------- + in_file_path : str + + Returns + ------- + Dict + dict - containing all _blocks as keys (Title, Eneversion, num_trials {1:{}, 2:{} ....}) """ - Needs output for checknig. - Simple tre_ read - reads only _blocks! does not seperate fields. - rather ugly! but not much time! - Parameters - ---------- - in_file_path : str - - Returns - ------- - Dict - dict - containing all _blocks as keys (Title, Eneversion, num_trials {1:{}, 2:{} ....}) - """ data = {"TIMESTEP": {}} @@ -932,36 +981,36 @@ def read_trc(in_file_path:str, every_step:int=1, verbose:bool=True)->Dict: skipFrame = False doKeepFrameData = lambda step_number: step_number == 0 or step_number % every_step == 0 - with open(in_file_path, 'r') as infile: + with open(in_file_path, "r") as infile: for line in infile: if isBlockTitle: # BlockHeader - if ("TITLE" in line): - if(isFirstTitleBlock): # only keep one title block + if "TITLE" in line: + if isFirstTitleBlock: # only keep one title block key = line.strip() isFirstTitleBlock = False else: skipBlockLines = True - elif ("TIMESTEP" in line): - if (doKeepFrameData(timestep)): # store data starts with - if(timestep != 0 ): + elif "TIMESTEP" in line: + if doKeepFrameData(timestep): # store data starts with + if timestep != 0: data["TIMESTEP"].update(frameSubBlocks) timestep += 1 vals = next(infile).split() frameSubBlocks = {timestep: {"steps": int(vals[0]), "time": float(vals[1])}} - skipFrame=False + skipFrame = False else: timestep += 1 - skipFrame=True + skipFrame = True skipBlockLines = True - elif("POSITIONRED" in line or "GENBOX" in line): #Known TRC subblocks + elif "POSITIONRED" in line or "GENBOX" in line: # Known TRC subblocks isFrameSubBlock = True key = line.strip() else: - raise IOError("Found a not known trc block: "+line.strip()) + raise IOError("Found a not known trc block: " + line.strip()) isBlockTitle = False continue - elif "END" in line: # BlockEnds + elif "END" in line: # BlockEnds if skipBlockLines or skipFrame: skipBlockLines = False elif isFrameSubBlock: @@ -979,79 +1028,88 @@ def read_trc(in_file_path:str, every_step:int=1, verbose:bool=True)->Dict: block.append(line) continue - if (not isBlockTitle): + if not isBlockTitle: frame_keys = list(frameSubBlocks.keys()) print(frame_keys) - warnings.warn("total number of frames: "+str(len(frame_keys))) + warnings.warn("total number of frames: " + str(len(frame_keys))) del frameSubBlocks[frame_keys[-1]] - #raise IOError("The Final gromos Block was not terminated by an END!") + # raise IOError("The Final gromos Block was not terminated by an END!") # lastBlock - if (timestep != 0 and len(frameSubBlocks) > 0): + if timestep != 0 and len(frameSubBlocks) > 0: data["TIMESTEP"].update(frameSubBlocks) return data -def read_gromos_csv(fileName, sep=' '): - with open(fileName, 'r') as infile: + +def read_gromos_csv(fileName, sep=" "): + with open(fileName, "r") as infile: header = next(infile).replace("#", "").split() - data_dict ={x:[] for x in header} + data_dict = {x: [] for x in header} for line in infile: words = list(filter(None, line.strip().split(sep))) - for index,x in enumerate(header): + for index, x in enumerate(header): try: data_dict[x].append(float(words[index])) except IndexError: - print('WARNING: Line in %s contains too few columns: %s' % (fileName, line)) + print("WARNING: Line in %s contains too few columns: %s" % (fileName, line)) return data_dict -def read_ene_ana_lib(in_path:str): + +def read_ene_ana_lib(in_path: str): with open(in_path, "r") as infile: lines = infile.readlines() block_lines = _read_gromos_block(lines) block_set = {} for block_title in block_lines: - #print(block_title) - if(block_title in ["TITLE", "ENEVERSION"]): - block_set.update({block_title:{"content": block_lines[block_title]}}) + # print(block_title) + if block_title in ["TITLE", "ENEVERSION"]: + block_set.update({block_title: {"content": block_lines[block_title]}}) - elif (block_title in ["ENERTRJ", "FRENERTRJ"]): + elif block_title in ["ENERTRJ", "FRENERTRJ"]: comments = [] block_dict = {} current_block = False for line in block_lines[block_title]: - if(line.strip().startswith("#")): + if line.strip().startswith("#"): comments.append(line) - elif(line.strip().startswith("block")): + elif line.strip().startswith("block"): current_block = line.replace("block", "").strip() - block_dict.update({current_block:{}}) - elif(line.strip().startswith("subblock")): - if(not "subblock" in block_dict[current_block]): - block_dict[current_block].update({"subblock":[line.replace("subblock", "").strip().split()]}) + block_dict.update({current_block: {}}) + elif line.strip().startswith("subblock"): + if not "subblock" in block_dict[current_block]: + block_dict[current_block].update( + {"subblock": [line.replace("subblock", "").strip().split()]} + ) else: block_dict[current_block]["subblock"].append(line.replace("subblock", "").strip().split()) - elif (line.strip().startswith("size")): - if(not "size" in block_dict[current_block]): - block_dict[current_block].update({"size":[line.replace("size", "").strip()]}) + elif line.strip().startswith("size"): + if not "size" in block_dict[current_block]: + block_dict[current_block].update({"size": [line.replace("size", "").strip()]}) else: block_dict[current_block]["size"].append(line.replace("size", "").strip()) else: - raise ValueError("Ene_ana did not understand line in "+current_block+": ", line) - block_set.update({block_title:{"comments":"".join(comments), "_blocks":block_dict}}) + raise ValueError("Ene_ana did not understand line in " + current_block + ": ", line) + block_set.update({block_title: {"comments": "".join(comments), "_blocks": block_dict}}) - elif (block_title == "VARIABLES"): + elif block_title == "VARIABLES": comments = [] block_dict = {} for line in block_lines[block_title]: - if(line.strip().startswith("#")): + if line.strip().startswith("#"): comments.append(line) else: var_name, var_value = line.split("=") - block_dict.update({var_name.strip():var_value.strip()}) + block_dict.update({var_name.strip(): var_value.strip()}) block_set.update({block_title: {"comments": "".join(comments), "variables": block_dict}}) else: - raise ValueError("FOUND A UKNOWN BLOCK! - PLEASE IMPLEMENT IT\n\t", block_title,"\n\t", "\t".join(block_lines[block_title])) + raise ValueError( + "FOUND A UKNOWN BLOCK! - PLEASE IMPLEMENT IT\n\t", + block_title, + "\n\t", + "\t".join(block_lines[block_title]), + ) return block_set diff --git a/pygromos/files/blocks/__init__.py b/pygromos/files/blocks/__init__.py index 92fd16e8..142e33e7 100644 --- a/pygromos/files/blocks/__init__.py +++ b/pygromos/files/blocks/__init__.py @@ -7,6 +7,6 @@ from pygromos.files.blocks._general_blocks import TITLE, TIMESTEP, TRAJ # forward declarations -TITLE:TITLE = TITLE -TIMESTEP:TIMESTEP = TIMESTEP -TRAJ:TRAJ = TRAJ \ No newline at end of file +TITLE: TITLE = TITLE +TIMESTEP: TIMESTEP = TIMESTEP +TRAJ: TRAJ = TRAJ diff --git a/pygromos/files/blocks/_general_blocks.py b/pygromos/files/blocks/_general_blocks.py index 0d353fa9..bbd68e59 100644 --- a/pygromos/files/blocks/_general_blocks.py +++ b/pygromos/files/blocks/_general_blocks.py @@ -3,8 +3,8 @@ import copy # FIELDS -class _generic_field(): - comment:str = "" +class _generic_field: + comment: str = "" fieldseperator = "\t" lineseperator = "\n" @@ -21,12 +21,14 @@ def __copy__(self): def to_string(self): raise NotImplementedError("to string method needs to be implemented!") + # BLOCKS ##genericblock: class _generic_gromos_block: comment: str - content:Iterable #some content - def __init__(self, name: str=None, used: bool=None, content:str=None): # content:str, + content: Iterable # some content + + def __init__(self, name: str = None, used: bool = None, content: str = None): # content:str, self.used = used self.name = name self.line_seperator = "\n" @@ -34,7 +36,6 @@ def __init__(self, name: str=None, used: bool=None, content:str=None): # conten self.comment_char = "#" self._check_import_method(content=content) - def __str__(self): return self.block_to_string() @@ -48,10 +49,9 @@ def __copy__(self): block = type(self)(name=self.name, used=self.used, content=self.content) return block - def __deepcopy__(self, memo): - #return block as string, split by line and cut block title and END - newContent= self.line_seperator.join(self.block_to_string().split(self.line_seperator)[1:-2]) + # return block as string, split by line and cut block title and END + newContent = self.line_seperator.join(self.block_to_string().split(self.line_seperator)[1:-2]) block = type(self)(content=newContent.split(self.line_seperator)) return block @@ -61,41 +61,43 @@ def __eq__(self, __o: object) -> bool: else: return False - - def _check_import_method(self, content:str = None): - if(not content is None): - if (isinstance(content, list) and all([isinstance(x, str) for x in content])): + def _check_import_method(self, content: str = None): + if not content is None: + if isinstance(content, list) and all([isinstance(x, str) for x in content]): self.read_content_from_str(content) elif type(content) == self.__class__: self.content = content elif isinstance(content, str): self.read_content_from_str(content=content.split(self.line_seperator)) else: - raise Exception("Generic Block did not understand the type of content \n content: \n"+str(content)) + raise Exception("Generic Block did not understand the type of content \n content: \n" + str(content)) else: self.content = [] def read_content_from_str(self, content: str): - if (isinstance(content, str)): + if isinstance(content, str): lines = content.split("\n") else: lines = content self.content = [] for field in lines: - if (not field.strip().startswith("#") and not len(field.strip()) == 0): + if not field.strip().startswith("#") and not len(field.strip()) == 0: self.content.append(field.strip().split()) - def block_to_string(self) -> str: result = self.name + self.line_seperator - if(isinstance(self.content, list) and len(self.content) > 0 and all([isinstance(x, str) for x in self.content])): + if isinstance(self.content, list) and len(self.content) > 0 and all([isinstance(x, str) for x in self.content]): result += self.field_seperator.join(self.content) + self.line_seperator - elif(isinstance(self.content, list) and len(self.content) > 0 and all([isinstance(x, list) and all([isinstance(y, str) for y in x]) for x in self.content])): - result += self.line_seperator.join(map(lambda x: self.field_seperator.join(x), self.content)) - elif(isinstance(self.content, (str, Number))): - result+= self.field_seperator+str(self.content)+self.line_seperator + elif ( + isinstance(self.content, list) + and len(self.content) > 0 + and all([isinstance(x, list) and all([isinstance(y, str) for y in x]) for x in self.content]) + ): + result += self.line_seperator.join(map(lambda x: self.field_seperator.join(x), self.content)) + elif isinstance(self.content, (str, Number)): + result += self.field_seperator + str(self.content) + self.line_seperator else: - result += self.field_seperator + "EMPTY"+self.line_seperator + result += self.field_seperator + "EMPTY" + self.line_seperator result += self.line_seperator + "END" + self.line_seperator return result @@ -105,7 +107,8 @@ def get_name(self): class _iterable_gromos_block(_generic_gromos_block): table_header = [""] - def __init__(self, name: str, used: bool, content = None): + + def __init__(self, name: str, used: bool, content=None): self._content = [] super().__init__(name, used, content=content) @@ -114,8 +117,8 @@ def content(self): return self._content @content.setter - def content(self, content:Iterable): - self._content= content + def content(self, content: Iterable): + self._content = content def __getitem__(self, item: int): return self.content[item] @@ -126,35 +129,36 @@ def __len__(self): def append(self, obj): self.content.append(obj) - def extend(self, it:Iterable): + def extend(self, it: Iterable): self.content.extend(it) def block_to_string(self) -> str: result = self.name + self.line_seperator - result+= "#"+self.field_seperator+self.field_seperator.join(self.table_header)+ "\n" + result += "#" + self.field_seperator + self.field_seperator.join(self.table_header) + "\n" for x in self.content: result += x.to_string() result += "END\n" return result + ##GENERAL class TIMESTEP(_generic_gromos_block): step: int t: float - def __init__(self, t: float=None, step: int=None, content=None, subcontent=False, name="TIMESTEP", used=True): + def __init__(self, t: float = None, step: int = None, content=None, subcontent=False, name="TIMESTEP", used=True): - if(t is None and step is None): + if t is None and step is None: super().__init__(used=used, name=name, content=content) - elif(content is None): + elif content is None: super().__init__(used=used, name=name, content=None) - self.t=t - self.step =step + self.t = t + self.step = step self.subcontent = subcontent - def read_content_from_str(self, content:List[str]): + def read_content_from_str(self, content: List[str]): content = content[0].strip().split() self.content = content self.t = float(content[1]) @@ -166,14 +170,15 @@ def block_to_string(self) -> str: result += "END\n" return result + class TITLE(_generic_gromos_block): - content:str - field_seperator:str = "\t" - line_seperator:str = "\n" + content: str + field_seperator: str = "\t" + line_seperator: str = "\n" order = [[["content"]]] - pyGromosWatermark:str = ">>> Generated with PyGromosTools (riniker group) <<<" + pyGromosWatermark: str = ">>> Generated with PyGromosTools (riniker group) <<<" - def __init__(self, content:str, field_seperator:str="\t", line_seperator:str="\n", name="TITLE", used=True): + def __init__(self, content: str, field_seperator: str = "\t", line_seperator: str = "\n", name="TITLE", used=True): super().__init__(used=used, name=name, content=content) self.field_seperator = field_seperator self.line_seperator = line_seperator @@ -183,7 +188,7 @@ def __deepcopy__(self, memo): block.content = copy.deepcopy(self.content) return block - def read_content_from_str(self, content:List[str]): + def read_content_from_str(self, content: List[str]): if type(content) == str: self.content = [content] else: @@ -193,13 +198,15 @@ def block_to_string(self) -> str: result = "" result += str(self.name) + self.line_seperator result += "".join(self.content) - if (self.pyGromosWatermark not in result): - result += self.line_seperator+self.field_seperator+self.pyGromosWatermark+self.line_seperator + if self.pyGromosWatermark not in result: + result += self.line_seperator + self.field_seperator + self.pyGromosWatermark + self.line_seperator result += "END" + self.line_seperator return result + class TRAJ(_iterable_gromos_block): - content:Iterable + content: Iterable + def __init__(self, timestep_blocks: Iterable): super().__init__(used=True, name="Trajectory") self.content = timestep_blocks @@ -207,6 +214,3 @@ def __init__(self, timestep_blocks: Iterable): def block_to_string(self) -> str: return self.name + " contains \t" + str(len(self.content)) - - - diff --git a/pygromos/files/blocks/coord_blocks.py b/pygromos/files/blocks/coord_blocks.py index ecae32b5..62f0bb3e 100644 --- a/pygromos/files/blocks/coord_blocks.py +++ b/pygromos/files/blocks/coord_blocks.py @@ -8,27 +8,30 @@ from pygromos.files import blocks # forward declarations -TITLE:TITLE = TITLE -TIMESTEP:TIMESTEP = TIMESTEP -TRAJ:TRAJ = TRAJ +TITLE: TITLE = TITLE +TIMESTEP: TIMESTEP = TIMESTEP +TRAJ: TRAJ = TRAJ ########################################################################## # ENUMS ########################################################################## + class Pbc(Enum): trunc_octahedron = -1 vacuum = 0 rectangular = 1 triclinic = 2 + ########################################################################## # FIELDS ########################################################################## + class atomP(_generic_field): - def __init__(self, resID:int, resName:str, atomType:str, atomID:int, xp:float, yp:float, zp:float): + def __init__(self, resID: int, resName: str, atomType: str, atomID: int, xp: float, yp: float, zp: float): """ Parameters @@ -50,12 +53,13 @@ def __init__(self, resID:int, resName:str, atomType:str, atomID:int, xp:float, y self.zp = zp def to_string(self) -> str: - return "{: >5} {: <5} {: <6} {: >5}{: 15.9f}{:15.9f}{:15.9f}\n".format(self.resID, self.resName, self.atomType, self.atomID, self.xp, - self.yp, self.zp) + return "{: >5} {: <5} {: <6} {: >5}{: 15.9f}{:15.9f}{:15.9f}\n".format( + self.resID, self.resName, self.atomType, self.atomID, self.xp, self.yp, self.zp + ) class atomV(_generic_field): - def __init__(self, resID:int, resName:str, atomType:str, atomID:int, xv:float, yv:float, zv:float): + def __init__(self, resID: int, resName: str, atomType: str, atomID: int, xv: float, yv: float, zv: float): self.resID = resID self.resName = resName self.atomType = atomType @@ -65,12 +69,13 @@ def __init__(self, resID:int, resName:str, atomType:str, atomID:int, xv:float, y self.zv = zv def to_string(self) -> str: - return "{: >5} {: >3} {: <5}{: >7}{: 15.9f}{:15.9f}{:15.9f}\n".format(self.resID, self.resName, self.atomType, self.atomID, self.xv, - self.yv, self.zv) + return "{: >5} {: >3} {: <5}{: >7}{: 15.9f}{:15.9f}{:15.9f}\n".format( + self.resID, self.resName, self.atomType, self.atomID, self.xv, self.yv, self.zv + ) class lattice_shift(_generic_field): - def __init__(self, atomID:int, x:float, y:float, z:float): + def __init__(self, atomID: int, x: float, y: float, z: float): self.atomID = atomID self.x = x self.y = y @@ -79,6 +84,7 @@ def __init__(self, atomID:int, x:float, y:float, z:float): def to_string(self) -> str: return "{:>10}{:>10}{:>10}\n".format(self.x, self.y, self.z) + class atomSI(_generic_field): def __init__(self, resID: int, resName: str, atomType: str, atomID: int, sxx: float, sxy: float, sxz: float): self.resID = resID @@ -90,8 +96,10 @@ def __init__(self, resID: int, resName: str, atomType: str, atomID: int, sxx: fl self.sxz = sxz def to_string(self) -> str: - return "{: >5} {: >3} {: <5}{: >7}{: 15.9f}{:15.9f}{:15.9f}\n".format(self.resID, self.resName, self.atomType, self.atomID, self.sxx, - self.sxy, self.sxz) + return "{: >5} {: >3} {: <5}{: >7}{: 15.9f}{:15.9f}{:15.9f}\n".format( + self.resID, self.resName, self.atomType, self.atomID, self.sxx, self.sxy, self.sxz + ) + ########################################################################## # BLOCKS @@ -100,79 +108,118 @@ def to_string(self) -> str: class POSITION(_iterable_gromos_block): """ - POSITION + POSITION - Parameters - ---------- - content: List[atomP] - every element in this list is of atom position obj + Parameters + ---------- + content: List[atomP] + every element in this list is of atom position obj """ + def __init__(self, content: List[atomP]): super().__init__(used=True, name="POSITION", content=content) def _check_import_method(self, content: str): - if (isinstance(content, list) and all([isinstance(x, atomP) for x in content])): + if isinstance(content, list) and all([isinstance(x, atomP) for x in content]): self.content = content elif isinstance(content, str): self.read_content_from_str(content=content.split(self.line_seperator)) - elif (isinstance(content, list) and all([isinstance(x, str) for x in content])): + elif isinstance(content, list) and all([isinstance(x, str) for x in content]): self.read_content_from_str(content=content) elif content is None: self.content = [] else: - raise Exception("Generic Block did not understand the type of content \n content: \n"+str(content)) + raise Exception("Generic Block did not understand the type of content \n content: \n" + str(content)) - def read_content_from_str(self, content:List[str]): + def read_content_from_str(self, content: List[str]): lines = list(map(lambda x: x.split(), content)) - self.content = [blocks.coords.atomP(resID=int(x[0]), resName=str(x[1]), atomType=str(x[2]), atomID=int(x[3]), xp=float(x[4]), - yp=float(x[5]), zp=float(x[6])) for x in list(map(lambda x: x.split(), content)) if(not x[0] == "#")] + self.content = [ + blocks.coords.atomP( + resID=int(x[0]), + resName=str(x[1]), + atomType=str(x[2]), + atomID=int(x[3]), + xp=float(x[4]), + yp=float(x[5]), + zp=float(x[6]), + ) + for x in list(map(lambda x: x.split(), content)) + if (not x[0] == "#") + ] + class POSRESSPEC(_iterable_gromos_block): """ - POSITION + POSITION - Parameters - ---------- - content: List[atomP] - every element in this list is of atom position obj + Parameters + ---------- + content: List[atomP] + every element in this list is of atom position obj """ + def __init__(self, content: List[atomP]): super().__init__(used=True, name="POSRESSPEC", content=content) - def read_content_from_str(self, content:List[str]): - self.content = [blocks.coords.atomP(resID=int(x[0]), resName=str(x[1]), atomType=str(x[2]), atomID=int(x[3]), xp=float(x[4]), - yp=float(x[5]), zp=float(x[6])) for x in list(map(lambda x: x.split(), content)) if(not x[0] == "#")] + def read_content_from_str(self, content: List[str]): + self.content = [ + blocks.coords.atomP( + resID=int(x[0]), + resName=str(x[1]), + atomType=str(x[2]), + atomID=int(x[3]), + xp=float(x[4]), + yp=float(x[5]), + zp=float(x[6]), + ) + for x in list(map(lambda x: x.split(), content)) + if (not x[0] == "#") + ] + class VELOCITY(_iterable_gromos_block): """ - VELOCITY + VELOCITY - Parameters - ---------- - content: List[atomV] - every element in this list is of atom velocity obj + Parameters + ---------- + content: List[atomV] + every element in this list is of atom velocity obj """ def __init__(self, content: List[atomV]): super().__init__(used=True, name="VELOCITY", content=content) - def read_content_from_str(self, content:List[str]): - self.content = [atomV(resID=int(x[0]), resName=str(x[1]), atomType=str(x[2]), atomID=int(x[3]), xv=float(x[4]), yv=float(x[5]), zv=float(x[6])) for x in list(map(lambda x: x.split(), content)) if(not x[0] == "#")] + def read_content_from_str(self, content: List[str]): + self.content = [ + atomV( + resID=int(x[0]), + resName=str(x[1]), + atomType=str(x[2]), + atomID=int(x[3]), + xv=float(x[4]), + yv=float(x[5]), + zv=float(x[6]), + ) + for x in list(map(lambda x: x.split(), content)) + if (not x[0] == "#") + ] + class STOCHINT(_iterable_gromos_block): """ - STOCHINT + STOCHINT - Parameters - ---------- - content: List[atomSI] - every element in this list is of atom stochastic interval obj + Parameters + ---------- + content: List[atomSI] + every element in this list is of atom stochastic interval obj - seed: str - contains the seed for the stochastic dynamics simulation + seed: str + contains the seed for the stochastic dynamics simulation """ def __init__(self, content: List[atomSI]): @@ -180,38 +227,52 @@ def __init__(self, content: List[atomSI]): def block_to_string(self) -> str: result = self.name + self.line_seperator - result+= "#"+self.field_seperator+self.field_seperator.join(self.table_header)+ "\n" + result += "#" + self.field_seperator + self.field_seperator.join(self.table_header) + "\n" for x in self.content: result += x.to_string() result += "# seed\n" - result+= self.seed - if result[-1] != '\n': - result += '\n' + result += self.seed + if result[-1] != "\n": + result += "\n" result += "END\n" return result - def read_content_from_str(self, content:List[str]): - if(content is str): + def read_content_from_str(self, content: List[str]): + if content is str: content = content.split("\n") - self.content = [blocks.coords.atomSI(resID=int(x[0]), resName=str(x[1]), atomType=str(x[2]), atomID=int(x[3]), sxx=float(x[4]), sxy=float(x[5]), - sxz=float(x[6])) for x in list(map(lambda x: x.split(), content[:-1])) if(not x[0] == "#")] - - #seed safety check + self.content = [ + blocks.coords.atomSI( + resID=int(x[0]), + resName=str(x[1]), + atomType=str(x[2]), + atomID=int(x[3]), + sxx=float(x[4]), + sxy=float(x[5]), + sxz=float(x[6]), + ) + for x in list(map(lambda x: x.split(), content[:-1])) + if (not x[0] == "#") + ] + + # seed safety check x = content[-1].split() - if(len(x) == 7): - raise ValueError("The seed of STOCHINT has a length of 7 pleas use longer once of check if seed is present! \nGOT: "+str(x)) + if len(x) == 7: + raise ValueError( + "The seed of STOCHINT has a length of 7 pleas use longer once of check if seed is present! \nGOT: " + + str(x) + ) else: self.seed = content[-1] class REFPOSITION(_iterable_gromos_block): """ - REFPOSITION + REFPOSITION - Parameters - ---------- - content: List[atomP] - every element in this list is of atom position obj + Parameters + ---------- + content: List[atomP] + every element in this list is of atom position obj """ @@ -227,29 +288,41 @@ def __init__(self, content: List[atomP]): super().__init__(used=True, name="REFPOSITION", content=content) def _check_import_method(self, content: str): - if (isinstance(content, list) and all([isinstance(x, atomP) for x in content])): + if isinstance(content, list) and all([isinstance(x, atomP) for x in content]): self.content = content elif isinstance(content, str): self.read_content_from_str(content=content.split(self.line_seperator)) - elif (isinstance(content, list) and all([isinstance(x, str) for x in content])): + elif isinstance(content, list) and all([isinstance(x, str) for x in content]): self.read_content_from_str(content=content) elif content is None: self.content = [] else: - raise Exception("Generic Block did not understand the type of content \n content: \n"+str(content)) + raise Exception("Generic Block did not understand the type of content \n content: \n" + str(content)) + + def read_content_from_str(self, content: List[str]): + self.content = [ + blocks.coords.atomP( + resID=int(x[0]), + resName=str(x[1]), + atomType=str(x[2]), + atomID=int(x[3]), + xp=float(x[4]), + yp=float(x[5]), + zp=float(x[6]), + ) + for x in list(map(lambda x: x.split(), content)) + if (not x[0] == "#") + ] - def read_content_from_str(self, content:List[str]): - self.content = [blocks.coords.atomP(resID=int(x[0]), resName=str(x[1]), atomType=str(x[2]), atomID=int(x[3]), xp=float(x[4]), - yp=float(x[5]), zp=float(x[6])) for x in list(map(lambda x: x.split(), content)) if(not x[0] == "#")] class LATTICESHIFTS(_iterable_gromos_block): """ - LATTICESHIFTS + LATTICESHIFTS - Parameters - ---------- - content: List[lattice_shift] - every element in this list is a lattice shift obj + Parameters + ---------- + content: List[lattice_shift] + every element in this list is a lattice shift obj """ @@ -263,32 +336,41 @@ def __init__(self, content: List[lattice_shift]): """ super().__init__(used=True, name="LATTICESHIFTS", content=content) - def read_content_from_str(self, content:List[str]): + def read_content_from_str(self, content: List[str]): subblock1 = list(map(lambda x: re.findall(r"[\w]+", x.strip()), content)) subblock2 = list(map(lambda x: [x.strip() for x in re.findall(r"[\W]+", x.strip())], content)) subblock = [] for number, sign in zip(subblock1, subblock2): - if("#" in sign): + if "#" in sign: continue - elif (len(sign) == 2): + elif len(sign) == 2: row = [number[0], sign[0] + number[1], sign[1] + number[2]] - elif (len(sign) == 3): + elif len(sign) == 3: row = [sign[0] + number[0], sign[1] + number[1], sign[2] + number[2]] else: raise Exception("This does not work! \n SIGN: " + str(sign) + "\n Number: " + str(number)) subblock.append(row) - if (all(len(x) == 3 for x in subblock)): - self.content = list(map(lambda c: blocks.coords.lattice_shift(atomID=int(c[0]), x=int(c[1][0]), y=int(c[1][1]), - z=int(c[1][2])), enumerate(subblock))) + if all(len(x) == 3 for x in subblock): + self.content = list( + map( + lambda c: blocks.coords.lattice_shift( + atomID=int(c[0]), x=int(c[1][0]), y=int(c[1][1]), z=int(c[1][2]) + ), + enumerate(subblock), + ) + ) else: short_lines = [str(x) for x in subblock if (len(x) != 3)] - raise IOError("inconsistent Atom LatticeShifts line lenghts (have to be =3 fields!). Problem in line: " + "\n\t".join(short_lines)) + raise IOError( + "inconsistent Atom LatticeShifts line lenghts (have to be =3 fields!). Problem in line: " + + "\n\t".join(short_lines) + ) class GENBOX(_generic_gromos_block): - '''GENBOX + """GENBOX This Block is representing the simulation Box in a coordinate file. @@ -301,10 +383,18 @@ class GENBOX(_generic_gromos_block): euler: List[float] origin: List[float] - ''' + """ - def __init__(self, pbc: Pbc=Pbc(0), length: List[float] = [0.0,0.0,0.0], angles: List[float] = [0.0,0.0,0.0], euler: List[float] = [0.0,0.0,0.0], origin: List[float] = [0.0,0.0,0.0], content=None): - ''' + def __init__( + self, + pbc: Pbc = Pbc(0), + length: List[float] = [0.0, 0.0, 0.0], + angles: List[float] = [0.0, 0.0, 0.0], + euler: List[float] = [0.0, 0.0, 0.0], + origin: List[float] = [0.0, 0.0, 0.0], + content=None, + ): + """ Parameters ---------- @@ -314,9 +404,9 @@ def __init__(self, pbc: Pbc=Pbc(0), length: List[float] = [0.0,0.0,0.0], angles: euler: List[float] origin: List[float] - ''' + """ - if(not content is None): + if not content is None: super().__init__(used=True, name="GENBOX", content=content) else: super().__init__(used=True, name="GENBOX") @@ -337,76 +427,85 @@ def block_to_string(self) -> str: return result - def read_content_from_str(self, content:List[str]): - if(len(content[0].split()) == 1): + def read_content_from_str(self, content: List[str]): + if len(content[0].split()) == 1: self._pbc = blocks.coords.Pbc(int(content[0].strip())) else: raise IOError("Could not read pbc information!") - if(len(content[1].split())== 3): + if len(content[1].split()) == 3: self._length = list(map(float, content[1].strip().split())) else: raise IOError("Could not read box length information!") - if(len(content[2].split())== 3): + if len(content[2].split()) == 3: self._angles = list(map(float, content[2].strip().split())) else: raise IOError("Could not read box angles information!") - if(len(content[3].split())== 3): + if len(content[3].split()) == 3: self._euler = list(map(float, content[3].strip().split())) else: raise IOError("Could not read box euler information!") - if(len(content[4].split())== 3): + if len(content[4].split()) == 3: self._origin = list(map(float, content[4].strip().split())) else: raise IOError("Could not read box origin information!") - #Attributes + # Attributes @property - def pbc(self)->Pbc: + def pbc(self) -> Pbc: return self._pbc + @pbc.setter def pbc(self, pbc: Pbc): - if(isinstance(pbc, Pbc)): + if isinstance(pbc, Pbc): self._pbc = pbc - elif(isinstance(pbc, int) or (isinstance(pbc, str) and pbc.isalnum())): - if(int(pbc) in Pbc._value2member_map_): + elif isinstance(pbc, int) or (isinstance(pbc, str) and pbc.isalnum()): + if int(pbc) in Pbc._value2member_map_: self._pbc = Pbc(int(pbc)) else: - raise ValueError("unknown int for pbc\n Use: \n"+str(Pbc.__members__)) + raise ValueError("unknown int for pbc\n Use: \n" + str(Pbc.__members__)) else: raise ValueError("Periodic boundary Condition must be int or PBC-Enum") + @property def length(self) -> List[float]: return self._length + @length.setter def length(self, length: List[float]): - if(isinstance(length, List) and all([isinstance(x, Number) for x in length])): + if isinstance(length, List) and all([isinstance(x, Number) for x in length]): self._length = length else: raise ValueError("length must be List[float]") + @property def angles(self) -> List[float]: return self._angles + @angles.setter def angles(self, angles: List[float]): - if(isinstance(angles, List) and all([isinstance(x, Number) for x in angles])): + if isinstance(angles, List) and all([isinstance(x, Number) for x in angles]): self._angles = angles else: raise ValueError("angles must be List[float]") + @property def euler(self) -> List[float]: return self._euler + @euler.setter def euler(self, euler: List[float]): - if(isinstance(euler, List) and all([isinstance(x, Number) for x in euler])): + if isinstance(euler, List) and all([isinstance(x, Number) for x in euler]): self._euler = euler else: raise ValueError("euler must be List[float]") + @property def origin(self) -> List[float]: return self._origin + @origin.setter def origin(self, origin: List[float]): - if(isinstance(origin, List) and all([isinstance(x, Number) for x in origin])): + if isinstance(origin, List) and all([isinstance(x, Number) for x in origin]): self._angles = origin else: raise ValueError("origin must be List[float]") @@ -415,6 +514,7 @@ def origin(self, origin: List[float]): class PERTDATA(_generic_gromos_block): content: float + def __init__(self, content: List[str]): """ This block is used for lambda-sampling and gives the lambda value of the current coordinates. @@ -426,13 +526,13 @@ def __init__(self, content: List[str]): """ super(PERTDATA, self).__init__(name=__class__.__name__, used=True, content=content) - def read_content_from_str(self, content:List[str]): + def read_content_from_str(self, content: List[str]): self.content = float("\n".join(content).strip()) @property - def lam(self)->float: + def lam(self) -> float: return self.content @lam.setter - def lam(self, lam:float): + def lam(self, lam: float): self.content = float(lam) diff --git a/pygromos/files/blocks/energy_blocks.py b/pygromos/files/blocks/energy_blocks.py index 7d349dce..dc108bde 100644 --- a/pygromos/files/blocks/energy_blocks.py +++ b/pygromos/files/blocks/energy_blocks.py @@ -1,10 +1,9 @@ - from pygromos.files.blocks._general_blocks import TITLE, TIMESTEP, TRAJ # forward declarations -TITLE:TITLE = TITLE -TIMESTEP:TIMESTEP = TIMESTEP -TRAJ:TRAJ = TRAJ +TITLE: TITLE = TITLE +TIMESTEP: TIMESTEP = TIMESTEP +TRAJ: TRAJ = TRAJ """ This was an Idea! @@ -44,5 +43,5 @@ def block_to_string(self) -> str: return result pass - -""" \ No newline at end of file + +""" diff --git a/pygromos/files/blocks/imd_blocks.py b/pygromos/files/blocks/imd_blocks.py index 11d01b16..0bf80665 100644 --- a/pygromos/files/blocks/imd_blocks.py +++ b/pygromos/files/blocks/imd_blocks.py @@ -32,31 +32,39 @@ def block_to_string(self) -> str: try: if isinstance(attribute, (str, Number, bool)): # One element field - if(isinstance(attribute, (bool, int))): + if isinstance(attribute, (bool, int)): attribute = int(attribute) - elif (isinstance(attribute, float)): # supress scientific notation for floats! + elif isinstance(attribute, float): # supress scientific notation for floats! attribute = format(attribute, "f") result += str(attribute) + self.field_seperator elif isinstance(attribute, List) and all( - [isinstance(x, (str, Number)) for x in attribute]): # list content - if (all([isinstance(x, str) for x in attribute])): + [isinstance(x, (str, Number)) for x in attribute] + ): # list content + if all([isinstance(x, str) for x in attribute]): result += self.field_seperator.join(attribute) + self.field_seperator - elif (all([isinstance(x, Number) for x in attribute])): + elif all([isinstance(x, Number) for x in attribute]): result += self.field_seperator.join(map(str, attribute)) + self.field_seperator else: raise ValueError( - "could not Interpret list: " + str(element) + "\t\n" + str(attribute) + "\nEOF\n") + "could not Interpret list: " + str(element) + "\t\n" + str(attribute) + "\nEOF\n" + ) elif isinstance(attribute, List) and all([isinstance(x, List) for x in attribute]): # matrices pre_parsed_rows = map(lambda x: self.field_seperator.join(map(str, x)), attribute) result += (self.line_seperator + self.field_seperator).join( - pre_parsed_rows) + self.field_seperator + pre_parsed_rows + ) + self.field_seperator else: result += (self.line_seperator + self.field_seperator).join( - map(self.field_seperator.join, attribute)) + self.field_seperator + map(self.field_seperator.join, attribute) + ) + self.field_seperator except: raise ValueError( - "Could not convert attribute " + str( - element) + " to string!\n value of attribute was: \n" + str(attribute) + "\nEOF\n") + "Could not convert attribute " + + str(element) + + " to string!\n value of attribute was: \n" + + str(attribute) + + "\nEOF\n" + ) result += self.line_seperator result += "END\n" @@ -70,23 +78,23 @@ def read_content_from_str(self, content: List[str]): # a new key line was found add values to class if len(contentlines) > 0: self._parse_key_content(keyLineNumb=keyLineNumb, contentlines=contentlines) - keyLineNumb +=1 # go next key line - contentlines = [] # reset content storage + keyLineNumb += 1 # go next key line + contentlines = [] # reset content storage else: # no key found -> add data to list to be later added to key fields = line.split(self.field_seperator) - while '' in fields: - fields.remove('') + while "" in fields: + fields.remove("") contentlines.append(fields) - # add fianl key after loop + # add fianl key after loop self._parse_key_content(keyLineNumb=keyLineNumb, contentlines=contentlines) - def _parse_key_content(self, keyLineNumb = 0, contentlines = []): - #print("----------------") - #print(contentlines) - #print(self._order[0]) - #print(keyLineNumb) - if len(contentlines) == 1: #it's a one liner + def _parse_key_content(self, keyLineNumb=0, contentlines=[]): + # print("----------------") + # print(contentlines) + # print(self._order[0]) + # print(keyLineNumb) + if len(contentlines) == 1: # it's a one liner if len(contentlines[0]) == len(self._order[0][keyLineNumb]): # found key-value match for key, field in zip(self._order[0][keyLineNumb], contentlines[0]): @@ -94,7 +102,7 @@ def _parse_key_content(self, keyLineNumb = 0, contentlines = []): key = self._clean_key_from_order(key=key) field = self._try_to_convert_field(field=field, key=key) setattr(self, key, field) - else: # parse multi line + else: # parse multi line if len(self._order[0][keyLineNumb]) == 1: # one key but multiple fields key = self._clean_key_from_order(key=self._order[0][keyLineNumb][0]) @@ -109,9 +117,9 @@ def _parse_key_content(self, keyLineNumb = 0, contentlines = []): setattr(self, key, field) def _clean_key_from_order(self, key) -> str: - #key = key.replace("("," ").replace("."," ") - #key.split(" ") - #return key[0] + # key = key.replace("("," ").replace("."," ") + # key.split(" ") + # return key[0] if "(" in key: return key.split("(")[0] if "." in key: @@ -123,9 +131,9 @@ def _clean_key_from_order(self, key) -> str: def _try_to_convert_field(self, field, key): if isinstance(field, str): try: - if(self.__annotations__[key] is bool): + if self.__annotations__[key] is bool: return bool(int(field)) # solves the type problem for simple types - return self.__annotations__[key](field) #solves the type problem for simple types + return self.__annotations__[key](field) # solves the type problem for simple types except: return field elif isinstance(field, list): @@ -134,14 +142,13 @@ def _try_to_convert_field(self, field, key): return [float(x) for x in field] except: return field - elif all([isinstance(x, list) for x in field]) and all([[isinstance(x, list)for x in y] for y in field]): + elif all([isinstance(x, list) for x in field]) and all([[isinstance(x, list) for x in y] for y in field]): try: return [[float(x) for x in y] for y in field] except: return field - class SYSTEM(_generic_imd_block): """System Block @@ -157,6 +164,7 @@ class SYSTEM(_generic_imd_block): """ + name: str = "SYSTEM" # fields @@ -165,7 +173,7 @@ class SYSTEM(_generic_imd_block): _order = [[["NPM", "NSM"]]] - def __init__(self, NPM:int=0, NSM:int=0, content=None): + def __init__(self, NPM: int = 0, NSM: int = 0, content=None): super().__init__(used=True, content=content) if content is None: self.NPM = int(NPM) @@ -173,7 +181,7 @@ def __init__(self, NPM:int=0, NSM:int=0, content=None): class STEP(_generic_imd_block): - """ Step Block + """Step Block This Block gives the number of simulation steps, @@ -197,7 +205,7 @@ class STEP(_generic_imd_block): _order = [[["NSTLIM", "T", "DT"]]] - def __init__(self, NSTLIM:int=0, T:float=0, DT:float=0, content=None): + def __init__(self, NSTLIM: int = 0, T: float = 0, DT: float = 0, content=None): super().__init__(used=True, content=content) if content is None: self.NSTLIM = int(NSTLIM) @@ -247,7 +255,7 @@ class REPLICA(_generic_imd_block): # NRET 10 # RET(1..NRET) - 300.0 320.0 340.0 360.0 380.0 + 300.0 320.0 340.0 360.0 380.0 400.0 420.0 440.0 460.0 480.0 # LRESCALE 1 @@ -268,6 +276,7 @@ class REPLICA(_generic_imd_block): END """ + name: str = "REPLICA" RETL: bool @@ -285,12 +294,33 @@ class REPLICA(_generic_imd_block): NREQUIL: int CONT: bool - _order = [[["RETL"], ["NRET"], ["RET(1 ... NRET)"], ["LRESCALE"], - ["NRELAM"], ["RELAM(1 ... NRELAM)"], ["RETS(1 ... NRELAM)"], ["NRETRIAL", "NREQUIL", "CONT"]]] - - def __init__(self, RETL: bool=False, NRET: int=0, RET: List[float]=[], LRESCALE: int=0, NRELAM: int=0, RELAM: List[float]=[], RETS: List[float]=[], - NRETRIAL: int=0, NREQUIL: int=0, - CONT: bool=False, content=None): + _order = [ + [ + ["RETL"], + ["NRET"], + ["RET(1 ... NRET)"], + ["LRESCALE"], + ["NRELAM"], + ["RELAM(1 ... NRELAM)"], + ["RETS(1 ... NRELAM)"], + ["NRETRIAL", "NREQUIL", "CONT"], + ] + ] + + def __init__( + self, + RETL: bool = False, + NRET: int = 0, + RET: List[float] = [], + LRESCALE: int = 0, + NRELAM: int = 0, + RELAM: List[float] = [], + RETS: List[float] = [], + NRETRIAL: int = 0, + NREQUIL: int = 0, + CONT: bool = False, + content=None, + ): super().__init__(used=True, content=content) if content is None: self.RETL = bool(RETL) @@ -312,26 +342,27 @@ def read_content_from_str(self, content: List[str]): try: setattr(self, "RETL", int(content[1].split()[0])) setattr(self, "NRET", int(content[3].split()[0])) - T_values = list(map(float, content[5].split())) - if(len(T_values)== self.NRET): + T_values = list(map(float, content[5].split())) + if len(T_values) == self.NRET: setattr(self, "RET", T_values) else: raise IOError("REPLICA: NRET was not equal to the number of Temperatures (RET) in IMD!") setattr(self, "LRESCALE", int(content[7].split()[0])) setattr(self, "NRELAM", int(content[9].split()[0])) - lambda_val = list(map(float, content[11].split())) - if(len(lambda_val)== self.NRELAM): + lambda_val = list(map(float, content[11].split())) + if len(lambda_val) == self.NRELAM: setattr(self, "RELAM", lambda_val) else: raise IOError("REPLICA: NRELAM was not equal to the number of lambda values (RELAM) in IMD!") lambda_timestep = list(map(float, content[13].split())) - if(len(lambda_timestep)== self.NRELAM): + if len(lambda_timestep) == self.NRELAM: setattr(self, "RETS", lambda_timestep) else: raise IOError("REPLICA: NRELAM was not equal to the number of lambda timestep values (RETS) in IMD!") - [setattr(self, key, int(value)) for key, value in zip(self._order[0][-1], content[-1].split()) ] + [setattr(self, key, int(value)) for key, value in zip(self._order[0][-1], content[-1].split())] except Exception as err: - raise IOError("Could not parse block from str - "+__class__.__name__+"\n"+str(err.args)) + raise IOError("Could not parse block from str - " + __class__.__name__ + "\n" + str(err.args)) + class NEW_REPLICA_EDS(_generic_imd_block): """REPLICA_EDS Block @@ -362,6 +393,7 @@ class NEW_REPLICA_EDS(_generic_imd_block): CONT: bool Is this a continuation run? """ + name: str = "REPLICA_EDS" REEDS: bool @@ -379,12 +411,31 @@ class NEW_REPLICA_EDS(_generic_imd_block): CONT: bool PERIODIC: int - _order = [[["REEDS"], ["NRES", "NUMSTATES", "NEOFF"], ["RES(1 ... NRES)"], - ["EIR(NUMSTATES x NRES)"], ["NRETRIAL", "NREQUIL", "CONT", "EDS_STAT_OUT", "PERIODIC"]]] - - def __init__(self, REEDS: bool=False, NRES: int=0, NUMSTATES: int=0, NEOFF: int=0, RES: List[float]=[], EIR: List[List[float]]=[[]], - NRETRIAL: int=0, NREQUIL: int=0, - EDS_STAT_OUT: int=0, CONT: bool=False, PERIODIC: int=0, content=None): + _order = [ + [ + ["REEDS"], + ["NRES", "NUMSTATES", "NEOFF"], + ["RES(1 ... NRES)"], + ["EIR(NUMSTATES x NRES)"], + ["NRETRIAL", "NREQUIL", "CONT", "EDS_STAT_OUT", "PERIODIC"], + ] + ] + + def __init__( + self, + REEDS: bool = False, + NRES: int = 0, + NUMSTATES: int = 0, + NEOFF: int = 0, + RES: List[float] = [], + EIR: List[List[float]] = [[]], + NRETRIAL: int = 0, + NREQUIL: int = 0, + EDS_STAT_OUT: int = 0, + CONT: bool = False, + PERIODIC: int = 0, + content=None, + ): super().__init__(used=True, content=content) if content is None: self.REEDS = bool(REEDS) @@ -408,22 +459,22 @@ def read_content_from_str(self, content: List[str]): setattr(self, "NRES", int(content[3].split()[0])) setattr(self, "NEOFF", int(content[3].split()[1])) setattr(self, "NUMSTATES", int(content[3].split()[2])) - s_values = list(map(float, content[5].split())) - if(len(s_values)== self.NRES): + s_values = list(map(float, content[5].split())) + if len(s_values) == self.NRES: setattr(self, "RES", s_values) else: raise IOError("REPLICA_EDS: NRES was not equal to the number of s-values in IMD!") EIR = [] - for ind in range(7, 7+self.NUMSTATES): + for ind in range(7, 7 + self.NUMSTATES): EIR_line = list(map(float, content[ind].split())) - if(len(EIR_line) != self.NRES): + if len(EIR_line) != self.NRES: raise IOError("REPLICA_EDS: NRES was not equal to the number of EIRs given in IMD!") EIR.append(EIR_line) setattr(self, "EIR", EIR) - [setattr(self, key, int(value)) for key, value in zip(self._order[0][-1], content[-1].split()) ] + [setattr(self, key, int(value)) for key, value in zip(self._order[0][-1], content[-1].split())] except Exception as err: - raise IOError("Could not parse block from str - "+__class__.__name__+"\n"+str(err.args)) + raise IOError("Could not parse block from str - " + __class__.__name__ + "\n" + str(err.args)) class REPLICA_EDS(_generic_imd_block): @@ -442,12 +493,29 @@ class REPLICA_EDS(_generic_imd_block): EDS_STAT_OUT: int CONT: bool - _order = [[["REEDS"], ["NRES", "NUMSTATES"], ["RES(1 ... NRES)"], - ["EIR(NUMSTATES x NRES)"], ["NRETRIAL", "NREQUIL", "CONT", "EDS_STAT_OUT"]]] - - def __init__(self, REEDS: bool=True, NRES: int=0, NUMSTATES: int=0, RES: List[float]=[0], EIR: List[List[float]]=[[0]], NRETRIAL: int=0, - NREQUIL: int=0, - EDS_STAT_OUT: int=0, CONT: bool=True, content=None): + _order = [ + [ + ["REEDS"], + ["NRES", "NUMSTATES"], + ["RES(1 ... NRES)"], + ["EIR(NUMSTATES x NRES)"], + ["NRETRIAL", "NREQUIL", "CONT", "EDS_STAT_OUT"], + ] + ] + + def __init__( + self, + REEDS: bool = True, + NRES: int = 0, + NUMSTATES: int = 0, + RES: List[float] = [0], + EIR: List[List[float]] = [[0]], + NRETRIAL: int = 0, + NREQUIL: int = 0, + EDS_STAT_OUT: int = 0, + CONT: bool = True, + content=None, + ): """REPLICA_EDS Block This block is controlling the REPLICA_EDS settings in gromos and is basically a mixture of EDS and RE block. (Don't use them when using this block!) @@ -494,23 +562,22 @@ def read_content_from_str(self, content: List[str]): setattr(self, "REEDS", int(content[1].split()[0])) setattr(self, "NRES", int(content[3].split()[0])) setattr(self, "NUMSTATES", int(content[3].split()[1])) - s_values = list(map(float, content[5].split())) - if(len(s_values)== self.NRES): + s_values = list(map(float, content[5].split())) + if len(s_values) == self.NRES: setattr(self, "RES", s_values) else: raise IOError("REPLICA_EDS: NRES was not equal to the number of s-values in IMD!") EIR = [] - for ind in range(7, 7+self.NUMSTATES): + for ind in range(7, 7 + self.NUMSTATES): EIR_line = list(map(float, content[ind].split())) - if(len(EIR_line) != self.NRES): + if len(EIR_line) != self.NRES: raise IOError("REPLICA_EDS: NRES was not equal to the number of EIRs given in IMD!") EIR.append(EIR_line) setattr(self, "EIR", EIR) - [setattr(self, key, int(value)) for key, value in zip(self._order[0][-1], content[-1].split()) ] + [setattr(self, key, int(value)) for key, value in zip(self._order[0][-1], content[-1].split())] except Exception as err: - raise IOError("Could not parse block from str - "+__class__.__name__+"\n"+str(err.args)) - + raise IOError("Could not parse block from str - " + __class__.__name__ + "\n" + str(err.args)) class BOUNDCOND(_generic_imd_block): @@ -538,7 +605,7 @@ class BOUNDCOND(_generic_imd_block): _order = [[["NTB", "NDFMIN"]]] - def __init__(self, NTB: int=0, NDFMIN: int=0, content=None): + def __init__(self, NTB: int = 0, NDFMIN: int = 0, content=None): super().__init__(used=True, content=content) if content is None: self.NTB = int(NTB) @@ -575,27 +642,28 @@ class STOCHDYN(_generic_imd_block): _order = [[["NTSD", "NTFR", "NSFR", "NBREF", "RCUTF", "CFRIC", "TEMPSD"]]] - def __init__(self, - NTSD: int=0, - NTFR: int=0, - NSFR: int=0, - NBREF: int=0, - RCUTF: float=0, - CFRIC: float=0, - TEMPSD: float=0, - content=None): + def __init__( + self, + NTSD: int = 0, + NTFR: int = 0, + NSFR: int = 0, + NBREF: int = 0, + RCUTF: float = 0, + CFRIC: float = 0, + TEMPSD: float = 0, + content=None, + ): super().__init__(used=True, content=content) if content is None: self.NTSD = int(NTSD) self.NTFR = int(NTFR) - self.NSFR =int(NSFR) + self.NSFR = int(NSFR) self.NBREF = int(NBREF) self.RCUTF = float(RCUTF) self.CFRIC = float(CFRIC) self.TEMPSD = float(TEMPSD) - class PERTURBATION(_generic_imd_block): """Pertubation Block @@ -637,6 +705,7 @@ class PERTURBATION(_generic_imd_block): 0.5 0.5 2 0 """ + name: str = "PERTURBATION" NTG: int @@ -648,11 +717,20 @@ class PERTURBATION(_generic_imd_block): NLAM: int NSCALE: int - _order = [[["NTG", "NRDGL", "RLAM", "DLAMT"], - ["ALPHLJ", "ALPHC", "NLAM", "NSCALE"]]] - - def __init__(self, NTG: int=0, NRDGL: int=0, RLAM: float=0, DLAMT: float=0, ALPHLJ: float=0, ALPHC: float=0, NLAM: int=0, - NSCALE: int=0, content=None): + _order = [[["NTG", "NRDGL", "RLAM", "DLAMT"], ["ALPHLJ", "ALPHC", "NLAM", "NSCALE"]]] + + def __init__( + self, + NTG: int = 0, + NRDGL: int = 0, + RLAM: float = 0, + DLAMT: float = 0, + ALPHLJ: float = 0, + ALPHC: float = 0, + NLAM: int = 0, + NSCALE: int = 0, + content=None, + ): super().__init__(used=True, content=content) if content is None: self.NTG = int(NTG) @@ -684,7 +762,7 @@ class PRECALCLAM(_generic_imd_block): _order = [[["NRLAM", "MINLAM", "MAXLAM"]]] - def __init__(self, NRLAM:int=0, MINLAM:float=0, MAXLAM: float=0, content=None): + def __init__(self, NRLAM: int = 0, MINLAM: float = 0, MAXLAM: float = 0, content=None): """ Can be used to caluclate multiple extra lambda values Parameters @@ -739,6 +817,7 @@ class MULTIBATH(_generic_imd_block): _generic_imd_block, _generic_gromos_block """ + name: str = "MULTIBATH" ALGORITHM: int @@ -751,13 +830,31 @@ class MULTIBATH(_generic_imd_block): COMBATH: List[int] IRBATH: List[int] - _order: List[List[str]] = [[["ALGORITHM"], ["NUM"], ["NBATHS"], ["TEMP0(1 ... NBATHS)", "TAU(1 ... NBATHS)"], - ["DOFSET"], ["LAST(1 ... DOFSET)", "COMBATH(1 ... DOFSET)", "IRBATH(1 ... DOFSET)"]]] - #num is not part of the imd file!? - - def __init__(self, ALGORITHM: int=0, NBATHS: int=0, TEMP0: List[float]=[], TAU: List[float]=[], DOFSET: int=0, LAST: List[int]=[], - COMBATH: List[int]=[], - IRBATH: List[int]=[], NUM: int = None, content=None): + _order: List[List[str]] = [ + [ + ["ALGORITHM"], + ["NUM"], + ["NBATHS"], + ["TEMP0(1 ... NBATHS)", "TAU(1 ... NBATHS)"], + ["DOFSET"], + ["LAST(1 ... DOFSET)", "COMBATH(1 ... DOFSET)", "IRBATH(1 ... DOFSET)"], + ] + ] + # num is not part of the imd file!? + + def __init__( + self, + ALGORITHM: int = 0, + NBATHS: int = 0, + TEMP0: List[float] = [], + TAU: List[float] = [], + DOFSET: int = 0, + LAST: List[int] = [], + COMBATH: List[int] = [], + IRBATH: List[int] = [], + NUM: int = None, + content=None, + ): if content is None: self.ALGORITHM = int(ALGORITHM) self.NUM = NUM @@ -778,7 +875,9 @@ def __init__(self, ALGORITHM: int=0, NBATHS: int=0, TEMP0: List[float]=[], TAU: if not len(LAST) == int(NBATHS): warnings.warn("Warning in MULTIBATH block. There must be the same number of BATHS and LAST parameters") if not len(LAST) == len(COMBATH): - warnings.warn("Warning in MULTIBATH block. There must be the same number of COMBATH and LAST parameters.") + warnings.warn( + "Warning in MULTIBATH block. There must be the same number of COMBATH and LAST parameters." + ) if not len(LAST) == len(IRBATH): warnings.warn("Warning in MULTIBATH block. There must be the same number of IRBATH and LAST parameters") super().__init__(used=True) @@ -788,27 +887,27 @@ def __init__(self, ALGORITHM: int=0, NBATHS: int=0, TEMP0: List[float]=[], TAU: def read_content_from_str(self, content: List[str]): try: setattr(self, self._order[0][0][0], int(content[1].split()[0])) - if ("NUM" in content[0]): + if "NUM" in content[0]: setattr(self, self._order[0][1][0], int(content[1].split()[1])) setattr(self, self._order[0][2][0], int(content[3].split()[0])) TEMP0 = [] TAU = [] # Read in the temperatures of each temp bath - for ind in range(5, 5+self.NBATHS): + for ind in range(5, 5 + self.NBATHS): fields = list(map(float, content[ind].split())) TEMP0.append(fields[0]) TAU.append(fields[1]) setattr(self, "TEMP0", TEMP0) setattr(self, "TAU", TAU) # Read in DOFSET - setattr(self, self._order[0][4][0], int(content[5+self.NBATHS+1].split()[0])) - + setattr(self, self._order[0][4][0], int(content[5 + self.NBATHS + 1].split()[0])) + LAST = [] - COMBATH=[] - IRBATH=[] + COMBATH = [] + IRBATH = [] # Read in the last atoms of each temp bath - for ind in range(5+3+self.NBATHS, 5+3+2*self.NBATHS): + for ind in range(5 + 3 + self.NBATHS, 5 + 3 + 2 * self.NBATHS): fields = list(map(float, content[ind].split())) LAST.append(fields[0]) COMBATH.append(fields[1]) @@ -818,12 +917,17 @@ def read_content_from_str(self, content: List[str]): setattr(self, "IRBATH", IRBATH) except Exception as err: - raise IOError("Could not parse "+__class__.__name__+" block!\n"+str(err.args)) - - - def adapt_multibath(self, last_atoms_bath: Dict[int, int], algorithm: int = None, num: int = None, T: (float, List[float]) = None, - TAU: float = None) -> None: - """ adapt_multibath + raise IOError("Could not parse " + __class__.__name__ + " block!\n" + str(err.args)) + + def adapt_multibath( + self, + last_atoms_bath: Dict[int, int], + algorithm: int = None, + num: int = None, + T: (float, List[float]) = None, + TAU: float = None, + ) -> None: + """adapt_multibath This function is adding each atom set into a single multibath. #TODO implementation not correct with com_bath and irbath! Works for super simple cases though @@ -843,60 +947,59 @@ def adapt_multibath(self, last_atoms_bath: Dict[int, int], algorithm: int = None None """ - if (T == None): - if (any([self.TEMP0[0] != T_test for T_test in self.TEMP0])): + if T == None: + if any([self.TEMP0[0] != T_test for T_test in self.TEMP0]): raise ValueError("Temperatures are not the same, this is not implemented in adapt multibath!") T = self.TEMP0[0] else: self.TEMP0 = [float(T) for x in range(len(self.TEMP0))] - if (TAU == None): - if (any([self.TAU[0] != T_test for T_test in self.TAU])): + if TAU == None: + if any([self.TAU[0] != T_test for T_test in self.TAU]): raise ValueError("Temperatures are not the same, this is not implemented in adapt multibath!") TAU = self.TAU[0] else: self.TAU = [float(TAU) for x in range(len(self.TAU))] - if (algorithm == None): + if algorithm == None: pass else: self.ALGORITHM = int(algorithm) - - if (num != None): + + if num != None: self.NUM = int(num) # TODO implementation not correct with com_bath and irbath! Works for super simple cases though - #print("MBATH") - #print(last_atoms_bath) - #print("\n") - #print(last_atoms_bath.values()) - #print("\n") - #print(set(last_atoms_bath.values())) + # print("MBATH") + # print(last_atoms_bath) + # print("\n") + # print(last_atoms_bath.values()) + # print("\n") + # print(set(last_atoms_bath.values())) self.NBATHS = len(set(last_atoms_bath.values())) self.DOFSET = len(last_atoms_bath) self.LAST = [int(last_atom) for last_atom in last_atoms_bath] self.COMBATH = [int(last_atoms_bath[last_atom]) for last_atom in last_atoms_bath] self.IRBATH = [int(last_atoms_bath[last_atom]) for last_atom in last_atoms_bath] - if (self.NBATHS != len(self.TEMP0)): + if self.NBATHS != len(self.TEMP0): self.TEMP0 = [float(self.TEMP0[0]) for x in range(self.NBATHS)] self.TAU = [float(self.TAU[0]) for x in range(self.NBATHS)] - def block_to_string(self) -> str: result = "" result += str(self.name) + "\n" result += "# " + self.field_seperator.join(self._order[0][0]) + "\n" result += " " + str(int(self.ALGORITHM)) + "\n" - - if(self.ALGORITHM == "2"): - if(self.NUM is None): + + if self.ALGORITHM == "2": + if self.NUM is None: raise Exception("You need to specify the NUM parameter for MULTIBATH if ALGORITHM is 2!") - + result += "# " + self.field_seperator.join(self._order[0][1]) + "\n" result += " " + str(self.NUM) + "\n" - + result += "# " + self.field_seperator.join(self._order[0][2]) + "\n" result += " " + str(int(self.NBATHS)) + "\n" result += "# " + self.field_seperator.join(self._order[0][3]) + "\n" @@ -906,36 +1009,44 @@ def block_to_string(self) -> str: result += " " + str(int(self.DOFSET)) + "\n" result += "# " + self.field_seperator.join(map(str, self._order[0][5])) + "\n" for index in range(len(self.LAST)): - result += " " + str(int(self.LAST[index])) + self.field_seperator + str(int(self.COMBATH[index])) + self.field_seperator + str( - int(self.IRBATH[index])) + "\n" + result += ( + " " + + str(int(self.LAST[index])) + + self.field_seperator + + str(int(self.COMBATH[index])) + + self.field_seperator + + str(int(self.IRBATH[index])) + + "\n" + ) result += "END\n" return result class PRESSURESCALE(_generic_imd_block): """PRESSURESCALE Block - This block controls the barostat of the simulation + This block controls the barostat of the simulation - Attributes - ----------- - COUPLE: int - off(0), calc(1), scale(2) - SCALE: int - off(0), iso(1), aniso(2), full(3), semianiso(4) - COMP: float - compessibility - TAUP: float - coupling strength - VIRIAL: int - none(0), atomic(1), group(2) - SEMIANISOTROPIC: List[int] - (semianisotropic couplings: X, Y, Z) - e.g. 1 1 2: x and y jointly coupled and z separately coupled - e.g. 0 0 1: constant area (xy-plane) and z coupled to a bath - PRES0: List[List[float]] - reference pressure + Attributes + ----------- + COUPLE: int + off(0), calc(1), scale(2) + SCALE: int + off(0), iso(1), aniso(2), full(3), semianiso(4) + COMP: float + compessibility + TAUP: float + coupling strength + VIRIAL: int + none(0), atomic(1), group(2) + SEMIANISOTROPIC: List[int] + (semianisotropic couplings: X, Y, Z) + e.g. 1 1 2: x and y jointly coupled and z separately coupled + e.g. 0 0 1: constant area (xy-plane) and z coupled to a bath + PRES0: List[List[float]] + reference pressure """ + name: str = "PRESSURESCALE" COUPLE: int @@ -947,10 +1058,20 @@ class PRESSURESCALE(_generic_imd_block): PRES0: List[List[float]] _order = [ - [["COUPLE", "SCALE", "COMP", "TAUP", "VIRIAL"], ["SEMIANISOTROPIC COUPLINGS(X, Y, Z)"], ["PRES0(1...3,1...3)"]]] - - def __init__(self, COUPLE: int=0, SCALE: int=0, COMP: float=0, TAUP: float=0, VIRIAL: int=0, SEMIANISOTROPIC: List[int]=[], - PRES0: List[List[float]]=[[0,0,0],[0,0,0],[0,0,0]], content=None): + [["COUPLE", "SCALE", "COMP", "TAUP", "VIRIAL"], ["SEMIANISOTROPIC COUPLINGS(X, Y, Z)"], ["PRES0(1...3,1...3)"]] + ] + + def __init__( + self, + COUPLE: int = 0, + SCALE: int = 0, + COMP: float = 0, + TAUP: float = 0, + VIRIAL: int = 0, + SEMIANISOTROPIC: List[int] = [], + PRES0: List[List[float]] = [[0, 0, 0], [0, 0, 0], [0, 0, 0]], + content=None, + ): super().__init__(used=True, content=content) if content is None: self.COUPLE = int(COUPLE) @@ -963,11 +1084,11 @@ def __init__(self, COUPLE: int=0, SCALE: int=0, COMP: float=0, TAUP: float=0, VI def read_content_from_str(self, content: List[str]): try: - [setattr(self, key, value)for key, value in zip(self._order[0][0], content[1].split())] - setattr(self,"SEMIANISOTROPIC", list(map(int, content[3].split()))) - setattr(self,"PRES0", [list(map(float, x.split())) for x in content[5:]]) + [setattr(self, key, value) for key, value in zip(self._order[0][0], content[1].split())] + setattr(self, "SEMIANISOTROPIC", list(map(int, content[3].split()))) + setattr(self, "PRES0", [list(map(float, x.split())) for x in content[5:]]) except Exception as err: - raise IOError("Could not read string for block "+__class__.__name__+"\n"+str(err.args)) + raise IOError("Could not read string for block " + __class__.__name__ + "\n" + str(err.args)) class FORCE(_generic_imd_block): @@ -988,6 +1109,7 @@ class FORCE(_generic_imd_block): List of last atoms for Energy subgroups. (NRE len == NEGR) """ + name: str = "FORCE" BONDS: bool @@ -1001,8 +1123,18 @@ class FORCE(_generic_imd_block): _order = [[["BONDS", "ANGLES", "IMPROPER", "DIHEDRAL", "ELECTROSTATIC", "VDW"], ["NEGR", "NRE"]]] - def __init__(self, BONDS: bool=True, ANGLES: bool=True, IMPROPER: bool=True, DIHEDRAL: bool=True, ELECTROSTATIC: bool=True, VDW: bool=True, - NEGR: int=0, NRE: List[int]=[], content=None): + def __init__( + self, + BONDS: bool = True, + ANGLES: bool = True, + IMPROPER: bool = True, + DIHEDRAL: bool = True, + ELECTROSTATIC: bool = True, + VDW: bool = True, + NEGR: int = 0, + NRE: List[int] = [], + content=None, + ): """ Args: BONDS: @@ -1023,17 +1155,17 @@ def __init__(self, BONDS: bool=True, ANGLES: bool=True, IMPROPER: bool=True, DIH self.VDW = bool(int(VDW)) try: self.NEGR = int(NEGR) - except : - if(isinstance(NEGR, list)): + except: + if isinstance(NEGR, list): self.NEGR = int(NEGR[0]) - NRE = NEGR[1:]+NRE + NRE = NEGR[1:] + NRE self.NRE = NRE super().__init__(used=True) else: super().__init__(used=True, content=content) - def _parse_key_content(self, keyLineNumb = 0, contentlines = []): + def _parse_key_content(self, keyLineNumb=0, contentlines=[]): if keyLineNumb == 0: for key, field in zip(self._order[0][keyLineNumb], contentlines[0]): # first bring key to attribute form @@ -1050,22 +1182,21 @@ def _parse_key_content(self, keyLineNumb = 0, contentlines = []): field = self._try_to_convert_field(field=contentlines[0][1:], key=key) setattr(self, key, field) - def read_content_from_str(self, content: List[str]): try: fields = content[1].split(self.field_seperator) - while '' in fields: - fields.remove('') + while "" in fields: + fields.remove("") self._parse_key_content(keyLineNumb=0, contentlines=[fields]) setattr(self, self._order[0][1][0], int(content[3].split()[0])) setattr(self, self._order[0][1][1], list(map(int, content[3].split()[1:]))) except Exception as err: - raise IOError("Could not parse FORCE block!\n"+str(err.args)) + raise IOError("Could not parse FORCE block!\n" + str(err.args)) def adapt_energy_groups(self, energy_groups: Dict[int, int]): """ Change the Force groups. - + Parameters ---------- residues : Dict[int, int] @@ -1076,7 +1207,6 @@ def adapt_energy_groups(self, energy_groups: Dict[int, int]): self.NEGR = len(energy_groups) self.NRE = [int(energy_groups[forceGroupID]) for forceGroupID in sorted(energy_groups)] - def __adapt_energy_groups(self, residues: Dict[str, Dict[int, int]]): """ Old REEDS option @@ -1097,16 +1227,16 @@ def __adapt_energy_groups(self, residues: Dict[str, Dict[int, int]]): # set Energy Group ammount self.NEGR = len(residues) # total ammount of Engergy groups - if ("SOLV" in residues and len(residues["SOLV"]) == 0): + if "SOLV" in residues and len(residues["SOLV"]) == 0: self.NEGR -= 1 # make residues sortable, dict_m = {} solvent_names = ["WAT", "SOLV"] for x in sorted(residues): - if (type(residues[x]) == dict and not x in dict_m and not x in solvent_names): + if type(residues[x]) == dict and not x in dict_m and not x in solvent_names: dict_m.update(residues[x]) - elif (x in dict_m and not x == "SOLV" and not x == "SOL"): + elif x in dict_m and not x == "SOLV" and not x == "SOL": raise Exception("Found mutliple residues for the same residue id!") # build up NRE @@ -1119,10 +1249,10 @@ def __adapt_energy_groups(self, residues: Dict[str, Dict[int, int]]): # add solvents to NRE, but only if there are solvents present_solvents = [x for x in residues if (x in solvent_names)] - if (len(present_solvents) > 0): - if ([isinstance(residues[x], dict) and residues[x] != 0 for x in present_solvents]): + if len(present_solvents) > 0: + if [isinstance(residues[x], dict) and residues[x] != 0 for x in present_solvents]: self.NRE.append(sum(residues["SOLV"].values()) + count) - elif ([isinstance(residues[x], int) and residues[x] != 0 for x in present_solvents]): + elif [isinstance(residues[x], int) and residues[x] != 0 for x in present_solvents]: self.NRE.append(residues["SOLV"] + count) @@ -1151,7 +1281,7 @@ class CONSTRAINT(_generic_imd_block): _order = [[["NTC"], ["NTCP", "NTCP0(1)"], ["NTCS", "NTCS0(1)"]]] - def __init__(self, NTC:int=0, NTCP:int=0, NTCP0:float=0, NTCS:int=0, NTCS0:float=0, content=None): + def __init__(self, NTC: int = 0, NTCP: int = 0, NTCP0: float = 0, NTCS: int = 0, NTCS0: float = 0, content=None): """ Args: NTC: @@ -1206,8 +1336,16 @@ class PAIRLIST(_generic_imd_block): _order = [[["ALGORITHM", "NSNB", "RCUTP", "RCUTL", "SIZE", "TYPE"]]] - def __init__(self, ALGORITHM: int=0, NSNB: int=0, RCUTP: float=0, RCUTL: float=0, SIZE: (str or float)=0, - TYPE:(str or bool)=False, content=None): + def __init__( + self, + ALGORITHM: int = 0, + NSNB: int = 0, + RCUTP: float = 0, + RCUTL: float = 0, + SIZE: (str or float) = 0, + TYPE: (str or bool) = False, + content=None, + ): """ Args: ALGORITHM: @@ -1334,16 +1472,49 @@ class NONBONDED(_generic_imd_block): NLRLJ: bool SLVDNS: float - _order = [[["NLRELE"], ["APPAK", "RCRF", "EPSRF", "NSLFEXCL"], ["NSHAPE", "ASHAPE", "NA2CLC", "TOLA2", "EPSLS"], - ["NKX", "NKY", "NKZ", "KCUT"], ["NGX", "NGY", "NGZ", "NASORD", "NFDORD", "NALIAS", "NSPORD"], - ["NQEVAL", "FACCUR", "NRDGRD", "NWRGRD"], ["NLRLJ", "SLVDNS"]]] - - def __init__(self, NLRELE: int=0, APPAK: float=0, RCRF: float=0, EPSRF: float=0, NSLFEXCL: bool=False, NSHAPE: int=0, - ASHAPE: float=0, NA2CLC: int=0, TOLA2: str=0, - EPSLS: float=0, - NKX: int=0, NKY: int=0, NKZ: int=0, KCUT: float=0, NGX: int=0, NGY: int=0, NGZ: int=0, NASORD: int=0, - NFDORD: int=0, NALIAS: int=0, NSPORD: int=0, NQEVAL: int=0, FACCUR: float=0, NRDGRD: bool=False, NWRGRD: bool=False, - NLRLJ: bool=False, SLVDNS: float=0, content=None): + _order = [ + [ + ["NLRELE"], + ["APPAK", "RCRF", "EPSRF", "NSLFEXCL"], + ["NSHAPE", "ASHAPE", "NA2CLC", "TOLA2", "EPSLS"], + ["NKX", "NKY", "NKZ", "KCUT"], + ["NGX", "NGY", "NGZ", "NASORD", "NFDORD", "NALIAS", "NSPORD"], + ["NQEVAL", "FACCUR", "NRDGRD", "NWRGRD"], + ["NLRLJ", "SLVDNS"], + ] + ] + + def __init__( + self, + NLRELE: int = 0, + APPAK: float = 0, + RCRF: float = 0, + EPSRF: float = 0, + NSLFEXCL: bool = False, + NSHAPE: int = 0, + ASHAPE: float = 0, + NA2CLC: int = 0, + TOLA2: str = 0, + EPSLS: float = 0, + NKX: int = 0, + NKY: int = 0, + NKZ: int = 0, + KCUT: float = 0, + NGX: int = 0, + NGY: int = 0, + NGZ: int = 0, + NASORD: int = 0, + NFDORD: int = 0, + NALIAS: int = 0, + NSPORD: int = 0, + NQEVAL: int = 0, + FACCUR: float = 0, + NRDGRD: bool = False, + NWRGRD: bool = False, + NLRLJ: bool = False, + SLVDNS: float = 0, + content=None, + ): super().__init__(used=True, content=content) if content is None: @@ -1439,9 +1610,20 @@ class INITIALISE(_generic_imd_block): _order = [[["NTIVEL", "NTISHK", "NTINHT", "NTINHB"], ["NTISHI", "NTIRTC", "NTICOM"], ["NTISTI"], ["IG", "TEMPI"]]] - def __init__(self, NTIVEL: bool=False, NTISHK: int=0, NTINHT: bool=False, NTINHB: bool=False, NTISHI: bool=False, NTIRTC: bool=False, NTICOM: int=0, - NTISTI: bool=False, IG: int=0, - TEMPI: float=0, content=None): + def __init__( + self, + NTIVEL: bool = False, + NTISHK: int = 0, + NTINHT: bool = False, + NTINHB: bool = False, + NTISHI: bool = False, + NTIRTC: bool = False, + NTICOM: int = 0, + NTISTI: bool = False, + IG: int = 0, + TEMPI: float = 0, + content=None, + ): """ Args: NTIVEL: @@ -1472,17 +1654,18 @@ def __init__(self, NTIVEL: bool=False, NTISHK: int=0, NTINHT: bool=False, NTINHB class COMTRANSROT(_generic_imd_block): """COMTRANSROT block - This block controls the center of mass translation and rotation removal. (flying ice cube problem) + This block controls the center of mass translation and rotation removal. (flying ice cube problem) - Attributes - ---------- + Attributes + ---------- - NSCM : int - controls system centre-of-mass (com) motion removal - 0: no com motion removal (default) - < 0: com translation and rotation are removed every abs(NSCM) steps. - > 0: com translation is removed every NSCM steps. + NSCM : int + controls system centre-of-mass (com) motion removal + 0: no com motion removal (default) + < 0: com translation and rotation are removed every abs(NSCM) steps. + > 0: com translation is removed every NSCM steps. """ + name: str = "COMTRANSROT" NSCM: int @@ -1516,19 +1699,29 @@ class QMMM(_generic_imd_block): Scale MM charges with (2/pi)*atan(x*(r_{mm}-r_{mm})). Values > 0.0 describe the scaling factor, values < 0.0 turn off scaling (default). """ + name: str = "QMMM" # fields - NTQMMM: int # Define if QM/MM is applied (1) or not (0, default) - NTQMSW: int # QM software package to use. Available options are MNDO (0, default), Turbomole (1), DFTB (2), MOPAC (3), ORCA (4), and XTB (5) - RCUTQ: float # Cutoff for inclusion of MM charge groups. If the value is 0, all particles are considered. - NTWQMMM: int # Write QM/MM related data to special trajectory every NTWQMMM step. Switch off with 0. - QMLJ: int # Define if LJ interaction is activated in the QM zone (1) or not (0). - MMSCAL: float # Scale MM charges with (2/pi)*atan(x*(r_{mm}-r_{mm})). Values > 0.0 describe the scaling factor, values < 0.0 turn off scaling (default). + NTQMMM: int # Define if QM/MM is applied (1) or not (0, default) + NTQMSW: int # QM software package to use. Available options are MNDO (0, default), Turbomole (1), DFTB (2), MOPAC (3), ORCA (4), and XTB (5) + RCUTQ: float # Cutoff for inclusion of MM charge groups. If the value is 0, all particles are considered. + NTWQMMM: int # Write QM/MM related data to special trajectory every NTWQMMM step. Switch off with 0. + QMLJ: int # Define if LJ interaction is activated in the QM zone (1) or not (0). + MMSCAL: float # Scale MM charges with (2/pi)*atan(x*(r_{mm}-r_{mm})). Values > 0.0 describe the scaling factor, values < 0.0 turn off scaling (default). _order = [[["NTQMMM", "NTQMSW", "RCUTQ", "NTWQMMM", "QMLJ", "MMSCAL"]]] - def __init__(self, NTQMMM:int=0, NTQMSW:int=0, RCUTQ:float=0.0, NTWQMMM:int=0, QMLJ:int=0, MMSCAL:float=-1.0, content=None): + def __init__( + self, + NTQMMM: int = 0, + NTQMSW: int = 0, + RCUTQ: float = 0.0, + NTWQMMM: int = 0, + QMLJ: int = 0, + MMSCAL: float = -1.0, + content=None, + ): super().__init__(used=True, content=content) if content is None: self.NTQMMM = int(NTQMMM) @@ -1538,33 +1731,43 @@ def __init__(self, NTQMMM:int=0, NTQMSW:int=0, RCUTQ:float=0.0, NTWQMMM:int=0, Q self.QMLJ = int(QMLJ) self.MMSCAL = float(MMSCAL) + class EDS(_generic_imd_block): """EDS block - This block is used in an EDS simulation. + This block is used in an EDS simulation. - Attributes - ----------- - NUMSTATES: int - EDS-States - S: float - smoothness parameter - EIR: List[float] - energy offsets - EDS: bool, optional - turn on EDS_simulation - ALPHLJ: float, optional - ALPHC: float, optional - FUNCTIONAL: int, optional - 1: Single s Hamiltonian (default) - 2: Hamiltonian with NUMSTATES*(NUMSTATES-1)/2 (pairwise) S parameters ==> changes type of S - 3: Hamiltonian with (NUMSTATES-1) S parameters ==> changes type of S + Attributes + ----------- + NUMSTATES: int + EDS-States + S: float + smoothness parameter + EIR: List[float] + energy offsets + EDS: bool, optional + turn on EDS_simulation + ALPHLJ: float, optional + ALPHC: float, optional + FUNCTIONAL: int, optional + 1: Single s Hamiltonian (default) + 2: Hamiltonian with NUMSTATES*(NUMSTATES-1)/2 (pairwise) S parameters ==> changes type of S + 3: Hamiltonian with (NUMSTATES-1) S parameters ==> changes type of S """ _order = [[["EDS"], ["ALPHLJ", "ALPHC"], ["FUNCTIONAL FORM"], ["NUMSTATES"], ["S"], ["EIR"]]] - def __init__(self, NUMSTATES: int=0, S: float=0, EIR: List[float]=[], EDS: bool = 1, ALPHLJ: float = 0.0, - ALPHC: float = 0.0, FUNCTIONAL: int = 1, content=None): + def __init__( + self, + NUMSTATES: int = 0, + S: float = 0, + EIR: List[float] = [], + EDS: bool = 1, + ALPHLJ: float = 0.0, + ALPHC: float = 0.0, + FUNCTIONAL: int = 1, + content=None, + ): super().__init__(used=True, content=content) if content is None: self.name = "EDS" @@ -1587,13 +1790,12 @@ def read_content_from_str(self, content: List[str]): setattr(self, "EIR", list(map(float, content[11].split()))) except Exception as err: - raise IOError("Could not parse block from str - "+__class__.__name__+"\n"+str(err.args)) + raise IOError("Could not parse block from str - " + __class__.__name__ + "\n" + str(err.args)) class DISTANCERES(_generic_imd_block): - """DISTANCERES Block + """DISTANCERES Block""" - """ name = "DISTANCERES" NTDIR: int @@ -1607,8 +1809,18 @@ class DISTANCERES(_generic_imd_block): _order = [[["NTDIR", "NTDIRA", "CDIR", "DIR0", "TAUDIR", "FORCESCALE", "VDIR", "NTWDIR"]]] - def __init__(self, NTDIR: int=0, NTDIRA: int=0, CDIR: int=0, DIR0: int=0, TAUDIR: int=0, FORCESCALE: int=0, VDIR: int=0, - NTWDIR: int=0, content=None): + def __init__( + self, + NTDIR: int = 0, + NTDIRA: int = 0, + CDIR: int = 0, + DIR0: int = 0, + TAUDIR: int = 0, + FORCESCALE: int = 0, + VDIR: int = 0, + NTWDIR: int = 0, + content=None, + ): """ Args: NTDIR: @@ -1635,26 +1847,26 @@ def __init__(self, NTDIR: int=0, NTDIRA: int=0, CDIR: int=0, DIR0: int=0, TAUDIR class POSITIONRES(_generic_imd_block): """POSITIONRES block - This block allows the managment of the Position Restraints during the Simulation. - - Attributes - ---------- - NTPOR: - 0..3 controls atom positions re(con)straining. - 0: no position re(con)straints (default) - 1: restraining with force constant CPOR - 2: restraining with force constant CPOR weighted by atomic B-factors - 3: constraining - NTPORB: - 0,1 controls reading of reference positions and B-factors - 0: read reference positions from startup file. - 1: read reference positions and B-factors from special file - NTPORS: - 0,1 controls scaling of reference positions upon pressure scaling - 0: do not scale reference positions - 1: scale reference positions - CPOR: - >= 0 position restraining force constant + This block allows the managment of the Position Restraints during the Simulation. + + Attributes + ---------- + NTPOR: + 0..3 controls atom positions re(con)straining. + 0: no position re(con)straints (default) + 1: restraining with force constant CPOR + 2: restraining with force constant CPOR weighted by atomic B-factors + 3: constraining + NTPORB: + 0,1 controls reading of reference positions and B-factors + 0: read reference positions from startup file. + 1: read reference positions and B-factors from special file + NTPORS: + 0,1 controls scaling of reference positions upon pressure scaling + 0: do not scale reference positions + 1: scale reference positions + CPOR: + >= 0 position restraining force constant """ name = "POSITIONRES" @@ -1677,9 +1889,9 @@ def __init__(self, NTPOR=0, NTPORB=0, NTPORS=0, CPOR=0, content=None): class PRINTOUT(_generic_imd_block): """PRINTOUT block - + This Block manages the output frequency into the .omd/std-out file. - + Attributes ---------- NTPR: int @@ -1688,6 +1900,7 @@ class PRINTOUT(_generic_imd_block): =1 perform dihedral angle transition monitoring """ + name: str = "PRINTOUT" NTPR: int @@ -1705,31 +1918,32 @@ def __init__(self, NTPR=0, NTPP=0, content=None): class ENERGYMIN(_generic_imd_block): """ENERGYMIN block - This block takes care of managing the Energyminimization controls. - - Attributes - ---------- - NTEM: int - controls energy minimisation mode. - 0: do not do energy minimisation (default) - 1: steepest-descent minimisation - 2: Fletcher-Reeves conjugate-gradient minimisation - 3: Polak-Ribiere conjugate-gradient minimisation - NCYC: int - >0 number of steps before resetting the conjugate-gradient search direction - =0 reset only if the energy grows in the search direction - DELE: float - >0.0 energy threshold for convergence - >0.0 (conjugate-gradient) RMS force threshold for convergence - DX0: float - >0.0 initial step size - DXM: float - >0.0 maximum step size - NMIN: float - >0 minimum number of minimisation steps - FLIM: float - >=0.0 limit force to maximum value (FLIM > 0.0 is not recommended) + This block takes care of managing the Energyminimization controls. + + Attributes + ---------- + NTEM: int + controls energy minimisation mode. + 0: do not do energy minimisation (default) + 1: steepest-descent minimisation + 2: Fletcher-Reeves conjugate-gradient minimisation + 3: Polak-Ribiere conjugate-gradient minimisation + NCYC: int + >0 number of steps before resetting the conjugate-gradient search direction + =0 reset only if the energy grows in the search direction + DELE: float + >0.0 energy threshold for convergence + >0.0 (conjugate-gradient) RMS force threshold for convergence + DX0: float + >0.0 initial step size + DXM: float + >0.0 maximum step size + NMIN: float + >0 minimum number of minimisation steps + FLIM: float + >=0.0 limit force to maximum value (FLIM > 0.0 is not recommended) """ + name = "ENERGYMIN" NTEM: int @@ -1742,7 +1956,17 @@ class ENERGYMIN(_generic_imd_block): _order = [["NTEM NCYC DELE DX0 DXM NMIN FLIM".split()]] - def __init__(self, NTEM:int=0, NCYC:int=0, DELE:float=0, DX0:float=0, DXM:float=0, NMIN:int=0, FLIM:float=0, content=None): + def __init__( + self, + NTEM: int = 0, + NCYC: int = 0, + DELE: float = 0, + DX0: float = 0, + DXM: float = 0, + NMIN: int = 0, + FLIM: float = 0, + content=None, + ): super().__init__(used=True, content=content) if content is None: self.NTEM = NTEM @@ -1753,6 +1977,7 @@ def __init__(self, NTEM:int=0, NCYC:int=0, DELE:float=0, DX0:float=0, DXM:float= self.NMIN = NMIN self.FLIM = FLIM + class WRITETRAJ(_generic_imd_block): """WRITETRAJ @@ -1795,6 +2020,7 @@ class WRITETRAJ(_generic_imd_block): >0: write block-averaged energy variables every |NTWB| steps (and free energies if NTWG > 0) trajectory """ + name = "WRITETRAJ" NTWX: int @@ -1807,8 +2033,17 @@ class WRITETRAJ(_generic_imd_block): _order = [[["NTWX", "NTWSE", "NTWV", "NTWF", "NTWE", "NTWG", "NTWB"]]] - def __init__(self, NTWX: int = 0, NTWSE: int = 0, NTWV: int = 0, NTWF: int = 0, NTWE: int = 0, NTWG: int = 0, - NTWB: int = 0, content=None): + def __init__( + self, + NTWX: int = 0, + NTWSE: int = 0, + NTWV: int = 0, + NTWF: int = 0, + NTWE: int = 0, + NTWG: int = 0, + NTWB: int = 0, + content=None, + ): """ Args: NTWX: @@ -1833,14 +2068,15 @@ def __init__(self, NTWX: int = 0, NTWSE: int = 0, NTWV: int = 0, NTWF: int = 0, class AMBER(_generic_imd_block): """AMBER block - Attributes - ---------- - Amber: bool - AMBSCAL: float + Attributes + ---------- + Amber: bool + AMBSCAL: float """ + name: str = "AMBER" Amber: bool @@ -1859,23 +2095,23 @@ def __init__(self, AMBER=0, AMBSCAL=0, content=None): class COVALENTFORM(_generic_imd_block): """COVALENTFORM Block - The COVALENTFORM Block manages the functional form of the Bonded contributions to the force field. - It is optional in an imd file to define the block. - - Attributes - ---------- - NTBBH: int - 0,1 controls bond-stretching potential - 0: quartic form (default) - 1: harmonic form - NTBAH: int - 0,1 controls bond-angle bending potential - 0: cosine-harmonic (default) - 1: harmonic - NTBDN: int - 0,1 controls torsional dihedral potential - 0: arbitrary phase shifts (default) - 1: phase shifts limited to 0 and 180 degrees. + The COVALENTFORM Block manages the functional form of the Bonded contributions to the force field. + It is optional in an imd file to define the block. + + Attributes + ---------- + NTBBH: int + 0,1 controls bond-stretching potential + 0: quartic form (default) + 1: harmonic form + NTBAH: int + 0,1 controls bond-angle bending potential + 0: cosine-harmonic (default) + 1: harmonic + NTBDN: int + 0,1 controls torsional dihedral potential + 0: arbitrary phase shifts (default) + 1: phase shifts limited to 0 and 180 degrees. """ name = "COVALENTFORM" @@ -1897,11 +2133,11 @@ def __init__(self, NTBBH=0, NTBAH=0, NTBDN=0, content=None): class INNERLOOP(_generic_imd_block): """INNERLOOP block - Attributes - ---------- - NTILM: int - NTILS: int - NGPUS: int + Attributes + ---------- + NTILM: int + NTILS: int + NGPUS: int """ name = "INNERLOOP" @@ -1938,6 +2174,7 @@ class LAMBDA(_generic_imd_block): ELI(1): float or List[float] """ + name: str = "LAMBDA" NTIL: int @@ -1950,11 +2187,26 @@ class LAMBDA(_generic_imd_block): DLI: List[float] ELI: List[float] - _order: List[List[str]] = [[["NTIL"], ["NTLI(1..)", "NILG1(1..)", "NILG2(1..)", "ALI(1..)", "BLI(1;;)", "CLI(1;;)", - "DLI(1;;)", "ELI(1;;)"]]] - - def __init__(self, NTIL: int=0, NTLI: List[int]=[], NILG1: List[int]=[], NILG2: List[int]=[], ALI: List[float]=[], - BLI: List[float]=[], CLI: List[float]=[], DLI: List[float]=[], ELI: List[float]=[], content=None): + _order: List[List[str]] = [ + [ + ["NTIL"], + ["NTLI(1..)", "NILG1(1..)", "NILG2(1..)", "ALI(1..)", "BLI(1;;)", "CLI(1;;)", "DLI(1;;)", "ELI(1;;)"], + ] + ] + + def __init__( + self, + NTIL: int = 0, + NTLI: List[int] = [], + NILG1: List[int] = [], + NILG2: List[int] = [], + ALI: List[float] = [], + BLI: List[float] = [], + CLI: List[float] = [], + DLI: List[float] = [], + ELI: List[float] = [], + content=None, + ): super().__init__(used=True, content=content) if content is None: self.NTIL = NTIL @@ -1999,34 +2251,32 @@ class ROTTRANS(_generic_imd_block): name: str = "ROTTRANS" - RTC: int + RTC: int RTCLAST: int _order = [[["RTC", "RTCLAST"]]] - def __init__(self, - RTC: int=0, - RTCLAST: int=0, - content=None): + def __init__(self, RTC: int = 0, RTCLAST: int = 0, content=None): super().__init__(used=True, content=content) if content is None: self.RTC = RTC self.RTCLAST = RTCLAST + class RANDOMNUMBERS(_generic_imd_block): """ Random Numbers Block """ + name: str = "RANDOMNUMBERS" NTRNG: int NTGSL: int - _order = [[["NTRNG"], - ["NTGSL"]]] + _order = [[["NTRNG"], ["NTGSL"]]] - def __init__(self, NTRNG: int=0, NTGSL: int=0, content=None): + def __init__(self, NTRNG: int = 0, NTGSL: int = 0, content=None): super().__init__(used=True, content=content) if content is None: self.NTRNG = int(NTRNG) - self.NTGSL = int(NTGSL) \ No newline at end of file + self.NTGSL = int(NTGSL) diff --git a/pygromos/files/blocks/miscBlocks.py b/pygromos/files/blocks/miscBlocks.py index 935637d7..8444b6c6 100644 --- a/pygromos/files/blocks/miscBlocks.py +++ b/pygromos/files/blocks/miscBlocks.py @@ -3,13 +3,15 @@ from collections import defaultdict from collections import defaultdict + ##ResidueLibBlocks + class RESIDUENAMELIB(_general_blocks._generic_gromos_block): fields = ["pdb_name", "g96top_name"] - pdb_top:defaultdict(list) + pdb_top: defaultdict(list) - def __init__(self, content:Union[str, List[str], Dict[str, Dict[str, str]]]): + def __init__(self, content: Union[str, List[str], Dict[str, Dict[str, str]]]): """ content is the content for the residuenamelib @@ -18,17 +20,23 @@ def __init__(self, content:Union[str, List[str], Dict[str, Dict[str, str]]]): content : Union[List[str], Dict[str, Dict[str, str]]] """ print(type(content)) - if(isinstance(content, list)): + if isinstance(content, list): super().__init__(self.__class__.__name__, used=True, content=content) - elif(isinstance(content, str)): + elif isinstance(content, str): print(content.split()) super().__init__(self.__class__.__name__, used=True, content=content.split("\n")) - elif(isinstance(content, (dict, defaultdict))): + elif isinstance(content, (dict, defaultdict)): super().__init__(self.__class__.__name__, used=True) self.pdb_top = content else: - raise ValueError("Class<"+str(self.__class__.__name__)+">:\t did not get appropriate data type.\n got: "+str(type(content))+"\n"+str(content)) - + raise ValueError( + "Class<" + + str(self.__class__.__name__) + + ">:\t did not get appropriate data type.\n got: " + + str(type(content)) + + "\n" + + str(content) + ) def read_content_from_str(self, content): self.pdb_top = defaultdict(list) @@ -36,24 +44,22 @@ def read_content_from_str(self, content): for pdb, top in tuples: self.pdb_top[pdb].append(top) - def block_to_string(self) -> str: result = self.name + self.line_seperator - result+= self.comment_char+self.field_seperator.join(self.fields)+self.line_seperator + result += self.comment_char + self.field_seperator.join(self.fields) + self.line_seperator for pdb, top in sorted(self.pdb_top.items()): for topI in top: - result += self.field_seperator+pdb+self.field_seperator+topI+self.line_seperator + result += self.field_seperator + pdb + self.field_seperator + topI + self.line_seperator result += "END" + self.line_seperator return result - class ATOMNAMELIB(_general_blocks._generic_gromos_block): fields = ["top_resn", "atom_pdb", "atom_top"] - pdb_top:defaultdict(dict) + pdb_top: defaultdict(dict) - def __init__(self, content:Union[List[str], Dict[str, Dict[str, str]]]): + def __init__(self, content: Union[List[str], Dict[str, Dict[str, str]]]): """ atom name translation lib part of the resn lib @@ -62,34 +68,52 @@ def __init__(self, content:Union[List[str], Dict[str, Dict[str, str]]]): content : Union[List[str], Dict[str, Dict[str, str]]] """ print(type(content)) - if(isinstance(content, list)): + if isinstance(content, list): super().__init__(self.__class__.__name__, used=True, content=content) - elif(isinstance(content, str)): + elif isinstance(content, str): print(content.split()) super().__init__(self.__class__.__name__, used=True, content=content.split("\n")) - elif(isinstance(content, (dict, defaultdict))): + elif isinstance(content, (dict, defaultdict)): super().__init__(self.__class__.__name__, used=True) self.pdb_top = content else: - raise ValueError("Class<"+str(self.__class__.__name__)+">:\tdid not get appropriate data type.\n got: "+str(type(content))+"\n"+str(content)) - + raise ValueError( + "Class<" + + str(self.__class__.__name__) + + ">:\tdid not get appropriate data type.\n got: " + + str(type(content)) + + "\n" + + str(content) + ) def read_content_from_str(self, content): self.pdb_top = defaultdict(list) - tuples = [(resn, pdb, top) for resn, pdb, top in list(map(lambda x: x.strip().split(), filter(lambda x: not x.startswith("#"), content)))] + tuples = [ + (resn, pdb, top) + for resn, pdb, top in list( + map(lambda x: x.strip().split(), filter(lambda x: not x.startswith("#"), content)) + ) + ] pdb_top = defaultdict(dict) for resn, pdb, top in tuples: pdb_top[resn].update({pdb: top}) self.pdb_top = pdb_top - def block_to_string(self) -> str: result = self.name + self.line_seperator - result+= self.comment_char+self.field_seperator.join(self.fields)+self.line_seperator + result += self.comment_char + self.field_seperator.join(self.fields) + self.line_seperator for resn in self.pdb_top: atom_dict = self.pdb_top[resn] for pdb, top in sorted(atom_dict.items()): - result += self.field_seperator+resn+self.field_seperator+pdb+self.field_seperator+top+self.line_seperator + result += ( + self.field_seperator + + resn + + self.field_seperator + + pdb + + self.field_seperator + + top + + self.line_seperator + ) result += "END" + self.line_seperator - return result \ No newline at end of file + return result diff --git a/pygromos/files/blocks/mtb_blocks.py b/pygromos/files/blocks/mtb_blocks.py index a931ac64..66761a5e 100644 --- a/pygromos/files/blocks/mtb_blocks.py +++ b/pygromos/files/blocks/mtb_blocks.py @@ -7,17 +7,18 @@ from pygromos.files.blocks.topology_blocks import FORCEFIELD, MAKETOPVERSION, TITLE from pygromos.files.blocks._general_blocks import _generic_gromos_block, _iterable_gromos_block, _generic_field + class MTBUILDBLSOLUTE(_generic_gromos_block): FORCEFIELD: FORCEFIELD MAKETOPVERSION: MAKETOPVERSION - def __init__(self, FORCEFIELD:FORCEFIELD = None, MAKETOPVERSION:MAKETOPVERSION = None, content=None): + def __init__(self, FORCEFIELD: FORCEFIELD = None, MAKETOPVERSION: MAKETOPVERSION = None, content=None): super().__init__(name=self.__class__.__name__, used=True, content=content) self.FORCEFIELD = FORCEFIELD self.MAKETOPVERSION = MAKETOPVERSION def read_content_from_str(self, content: str): - #first line + # first line first_line = content[0].split() self.filename = first_line[1] self.residuecode = first_line[3] @@ -30,32 +31,40 @@ def read_content_from_str(self, content: str): self.NMAT = int(content[6].split()[0]) self.NLIN = int(content[6].split()[1]) - #TODO: implement NLIN - itr = 6+4 + # TODO: implement NLIN + itr = 6 + 4 nmat_found = 0 - while nmat_found < self.NMAT and itr < (len(content)-10): + while nmat_found < self.NMAT and itr < (len(content) - 10): if content[itr].startswith("#"): itr += 1 continue else: atom, anm, iacm, mass, cgm, icgm, mae = content[itr].split()[7:] - - - - def block_to_string(self) -> str: - result = "MTBUILDBLSOLUTE"+self.line_seperator - result += "#@BLOCKTYPE "+self.filename+" BLK "+self.residuecode+" "+self.function+" TYPE "+self.type+" NAME "+self.fullname+self.line_seperator - result += "# building block"+self.line_seperator - result += "# RNME"+self.line_seperator - result += self.RNME+self.line_seperator - result += "# number of atoms, number of preceding exclusions"+self.line_seperator - result += "# NMAT NLIN"+self.line_seperator - result += str(self.NMAT)+self.field_seperator+str(self.NLIN)+self.line_seperator - result += "# preceding exclusions"+self.line_seperator - result += "#ATOM MAE MSAE"+self.line_seperator - result += "# atoms"+self.line_seperator - - result += "END"+self.line_seperator - return result \ No newline at end of file + result = "MTBUILDBLSOLUTE" + self.line_seperator + result += ( + "#@BLOCKTYPE " + + self.filename + + " BLK " + + self.residuecode + + " " + + self.function + + " TYPE " + + self.type + + " NAME " + + self.fullname + + self.line_seperator + ) + result += "# building block" + self.line_seperator + result += "# RNME" + self.line_seperator + result += self.RNME + self.line_seperator + result += "# number of atoms, number of preceding exclusions" + self.line_seperator + result += "# NMAT NLIN" + self.line_seperator + result += str(self.NMAT) + self.field_seperator + str(self.NLIN) + self.line_seperator + result += "# preceding exclusions" + self.line_seperator + result += "#ATOM MAE MSAE" + self.line_seperator + result += "# atoms" + self.line_seperator + + result += "END" + self.line_seperator + return result diff --git a/pygromos/files/blocks/pertubation_blocks.py b/pygromos/files/blocks/pertubation_blocks.py index d5b4ac25..f8709f9b 100644 --- a/pygromos/files/blocks/pertubation_blocks.py +++ b/pygromos/files/blocks/pertubation_blocks.py @@ -22,9 +22,7 @@ pertubation_lam_state_nonbonded.__module__ = "__main__" - class atom_mass_type(_generic_field): - def __init__(self, N: int, ATMAS: float, ATMASN: str, comment: str = ""): self.N = N self.ATMAS = ATMAS @@ -38,7 +36,9 @@ def to_string(self): class atom_eds_pertubation_state(_generic_field): state_format_pattern = " {:>3} {:>10.5f}" - def __init__(self, NR:int, NAME:str, STATES:Dict[int, pertubation_eds_state], ALPHLJ:float=1.0, ALPHCRF:float=1.0): + def __init__( + self, NR: int, NAME: str, STATES: Dict[int, pertubation_eds_state], ALPHLJ: float = 1.0, ALPHCRF: float = 1.0 + ): self.NR = int(NR) self.NAME = NAME self.STATES = STATES @@ -46,15 +46,28 @@ def __init__(self, NR:int, NAME:str, STATES:Dict[int, pertubation_eds_state], AL self.ALPHCRF = float(ALPHCRF) def to_string(self): - state_str = "".join([self.state_format_pattern.format(int(self.STATES[x].IAC), float(self.STATES[x].CHARGE)) for x in sorted(self.STATES)]) - format_str = "{:>5} {:>5}"+state_str+" {:10.5f} {:10.5f}\n" + state_str = "".join( + [ + self.state_format_pattern.format(int(self.STATES[x].IAC), float(self.STATES[x].CHARGE)) + for x in sorted(self.STATES) + ] + ) + format_str = "{:>5} {:>5}" + state_str + " {:10.5f} {:10.5f}\n" return format_str.format(self.NR, self.NAME, self.ALPHLJ, self.ALPHCRF) class atom_lam_pertubation_state(_generic_field): state_format_pattern = " {:>5} {:>5} {:>10.5f}" - def __init__(self, NR:int, RES:int, NAME:str, STATES:Dict[int, pertubation_lam_state_nonbonded], ALPHLJ:float=1.0, ALPHCRF:float=1.0): + def __init__( + self, + NR: int, + RES: int, + NAME: str, + STATES: Dict[int, pertubation_lam_state_nonbonded], + ALPHLJ: float = 1.0, + ALPHCRF: float = 1.0, + ): self.NR = int(NR) self.RES = int(RES) self.NAME = NAME @@ -63,9 +76,17 @@ def __init__(self, NR:int, RES:int, NAME:str, STATES:Dict[int, pertubation_lam_s self.ALPHCRF = float(ALPHCRF) def to_string(self): - state_str = "".join([self.state_format_pattern.format(int(self.STATES[x].IAC),float(self.STATES[x].MASS), float(self.STATES[x].CHARGE)) for x in sorted(self.STATES)]) - format_str = "{:>5} {:>5} {:>5}"+state_str+" {:10.5f} {:10.5f}\n" - return format_str.format(self.NR, self.RES, self.NAME, self.ALPHLJ, self.ALPHCRF) + state_str = "".join( + [ + self.state_format_pattern.format( + int(self.STATES[x].IAC), float(self.STATES[x].MASS), float(self.STATES[x].CHARGE) + ) + for x in sorted(self.STATES) + ] + ) + format_str = "{:>5} {:>5} {:>5}" + state_str + " {:10.5f} {:10.5f}\n" + return format_str.format(self.NR, self.RES, self.NAME, self.ALPHLJ, self.ALPHCRF) + class atom_lam_pertubation_state_bond(_generic_field): state_format_pattern = " {:>5}" @@ -78,9 +99,10 @@ def __init__(self, NR: int, atomI: int, atomJ: int, STATES: Dict[int, int]): def to_string(self): state_str = "".join([self.state_format_pattern.format(int(self.STATES[x])) for x in sorted(self.STATES)]) - format_str = "{:>5} {:>5}"+state_str+"\n" + format_str = "{:>5} {:>5}" + state_str + "\n" return format_str.format(self.atomI, self.atomJ) + class atom_lam_pertubation_state_angle(_generic_field): state_format_pattern = " {:>5}" @@ -93,8 +115,8 @@ def __init__(self, NR: int, atomI: int, atomJ: int, atomK: int, STATES: Dict[int def to_string(self): state_str = "".join([self.state_format_pattern.format(int(self.STATES[x])) for x in sorted(self.STATES)]) - format_str = "{:>5} {:>5} {:>5}"+state_str+"\n" - return format_str.format(self.atomI, self.atomJ, self.atomK) + format_str = "{:>5} {:>5} {:>5}" + state_str + "\n" + return format_str.format(self.atomI, self.atomJ, self.atomK) class atom_lam_pertubation_state_dihedral(_generic_field): @@ -110,17 +132,28 @@ def __init__(self, NR: int, atomI: int, atomJ: int, atomK: int, atomL: int, STAT def to_string(self): state_str = "".join([self.state_format_pattern.format(int(self.STATES[x])) for x in sorted(self.STATES)]) - format_str = "{:>5} {:>5} {:>5} {:>5}"+state_str+"\n" - return format_str.format(self.atomI, self.atomJ, self.atomK, self.atomL) + format_str = "{:>5} {:>5} {:>5} {:>5}" + state_str + "\n" + return format_str.format(self.atomI, self.atomJ, self.atomK, self.atomL) + """ BLOCKS """ ### NONBONDED + class MPERTATOM(_generic_gromos_block): - def __init__(self, NJLA: int=None, NPTB: int=None, STATEIDENTIFIERS:List[str]=[], STATEATOMHEADER: Tuple[str]= ['NR', 'NAME', 'ALPHLJ', 'ALPHCRF'], STATEATOMS:List[atom_eds_pertubation_state]=[], - dummy_IAC = 22, dummy_CHARGE=0.0, content:List[str]=None): + def __init__( + self, + NJLA: int = None, + NPTB: int = None, + STATEIDENTIFIERS: List[str] = [], + STATEATOMHEADER: Tuple[str] = ["NR", "NAME", "ALPHLJ", "ALPHCRF"], + STATEATOMS: List[atom_eds_pertubation_state] = [], + dummy_IAC=22, + dummy_CHARGE=0.0, + content: List[str] = None, + ): """ This block is used for lambda sampling to define the different states. @@ -142,7 +175,7 @@ def __init__(self, NJLA: int=None, NPTB: int=None, STATEIDENTIFIERS:List[str]=[] dummy atom charge type for perturbed atoms """ - if(content is None): + if content is None: super().__init__(used=True, name=__class__.__name__) self.NJLA = NJLA self.NPTB = NPTB @@ -156,8 +189,7 @@ def __init__(self, NJLA: int=None, NPTB: int=None, STATEIDENTIFIERS:List[str]=[] self.dummy_IAC = dummy_IAC self.dummy_CHARGE = dummy_CHARGE - - def read_content_from_str(self, content:List[str]): + def read_content_from_str(self, content: List[str]): field = 0 comment = "" NJLA = None @@ -168,55 +200,67 @@ def read_content_from_str(self, content:List[str]): first = True for line in content: # print(line) - if ("#" in line): + if "#" in line: comment = line else: - if (field > 3): - if (first): - STATEATOMHEADER = ["NR", "NAME", ] + if field > 3: + if first: + STATEATOMHEADER = [ + "NR", + "NAME", + ] [STATEATOMHEADER.extend(["IAC" + str(x), "CHARGE" + str(x)]) for x in range(1, self.NPTB + 1)] STATEATOMHEADER += ["ALPHLJ", "ALPHCRF"] self.STATEATOMHEADER = STATEATOMHEADER first = False state_line = {key: value for key, value in zip(self.STATEATOMHEADER, line.split())} - final_state_line = {key: state_line[key] for key in state_line if - (not "IAC" in key and not "CHARGE" in key)} + final_state_line = { + key: state_line[key] for key in state_line if (not "IAC" in key and not "CHARGE" in key) + } - states = {x: pertubation_eds_state(IAC=int(state_line["IAC" + str(x)]), - CHARGE=float(state_line["CHARGE" + str(x)])) for x in - range(1, 1 + self.NPTB)} + states = { + x: pertubation_eds_state( + IAC=int(state_line["IAC" + str(x)]), CHARGE=float(state_line["CHARGE" + str(x)]) + ) + for x in range(1, 1 + self.NPTB) + } final_state_line.update({"STATES": states}) STATEATOMS.append(atom_eds_pertubation_state(**final_state_line)) - elif (field == 0): + elif field == 0: NJLA, NPTB = tuple(map(int, line.split())) self.NJLA = NJLA self.NPTB = NPTB - elif (field == 1): + elif field == 1: STATEIDENTIFIERS = line.split() self.STATEIDENTIFIERS = STATEIDENTIFIERS field += 1 self.STATEATOMS = STATEATOMS - @property - def nStates(self)->int: + def nStates(self) -> int: return self.NPTB @property - def nTotalStateAtoms(self)->int: + def nTotalStateAtoms(self) -> int: return self.NJLA @property - def states(self)->dict: - return {self.STATEIDENTIFIERS[state-1]: {atom.NR: atom.STATES[state] for atom in sorted(self.STATEATOMS, key=lambda x: x.NR)} for state in range(1, self.NPTB+1)} + def states(self) -> dict: + return { + self.STATEIDENTIFIERS[state - 1]: { + atom.NR: atom.STATES[state] for atom in sorted(self.STATEATOMS, key=lambda x: x.NR) + } + for state in range(1, self.NPTB + 1) + } """ ADD FUNCTIONS """ + def add_state_atoms(self, state_atoms: List[atom_eds_pertubation_state]): """ This function can add states and atoms, but also overwrite state values of existing atoms. @@ -230,60 +274,60 @@ def add_state_atoms(self, state_atoms: List[atom_eds_pertubation_state]): """ - #some preperations: + # some preperations: dummy_state = pertubation_eds_state(IAC=self.dummy_IAC, CHARGE=self.dummy_CHARGE) insert_id = self.STATEATOMHEADER.index("ALPHLJ") - #find all new states + # find all new states unique_stateIDs = np.unique(np.concatenate([list(natom.STATES.keys()) for natom in state_atoms])) ## Todo: not urgent; state number adaptation ( present states 1,2,3,4 new state 8 - id should be 5 not 8) - unique_states = list(map(str, [ "state"+str(x) if isinstance(x, Number) else x for x in unique_stateIDs])) + unique_states = list(map(str, ["state" + str(x) if isinstance(x, Number) else x for x in unique_stateIDs])) - #insert new state IDs + # insert new state IDs off = 0 for unique_state in unique_stateIDs: - self.STATEATOMHEADER.insert(insert_id+off, "IAC"+str(unique_state)) - self.STATEATOMHEADER.insert(insert_id+off+1, "CHARGE"+str(unique_state)) - off+=2 + self.STATEATOMHEADER.insert(insert_id + off, "IAC" + str(unique_state)) + self.STATEATOMHEADER.insert(insert_id + off + 1, "CHARGE" + str(unique_state)) + off += 2 - #add new state names + # add new state names self.STATEIDENTIFIERS.extend(unique_states) - #increase the number of new states + # increase the number of new states self.NPTB += len(unique_states) - #1. Update already present atoms: + # 1. Update already present atoms: atomIDs = [atom.NR for atom in state_atoms] for atom in self.STATEATOMS: - if(atom.NR in atomIDs): + if atom.NR in atomIDs: new_atom = state_atoms[atomIDs.index(atom.NR)] atom.NAME = new_atom.NAME atom.STATES.update({key: val for key, val in new_atom.STATES.items()}) - #add missing dummies - #print(unique_stateIDs) + # add missing dummies + # print(unique_stateIDs) atom.STATES.update({key: dummy_state for key in unique_stateIDs if not key in atom.STATES}) - #remove present atom + # remove present atom del atomIDs[atomIDs.index(atom.NR)] else: - #add missing dummies + # add missing dummies atom.STATES.update({key: dummy_state for key in unique_stateIDs if not key in atom.STATES}) - - #2. add new atoms + # 2. add new atoms new_atoms = [atom for atom in state_atoms if (atom.NR in atomIDs)] for atom in new_atoms: - atom.STATES.update({key:dummy_state for key in range(1, self.NPTB+1) if (key not in atom.STATES)}) + atom.STATES.update({key: dummy_state for key in range(1, self.NPTB + 1) if (key not in atom.STATES)}) self.STATEATOMS.append(atom) - self.NJLA +=1 + self.NJLA += 1 """ DELETING FUNCTIONS """ - def delete_state(self, stateIDs:(int, List[int])=None, stateNames:(str, List[str])=None): + + def delete_state(self, stateIDs: (int, List[int]) = None, stateNames: (str, List[str]) = None): """ This function deletes an state column. @@ -296,40 +340,45 @@ def delete_state(self, stateIDs:(int, List[int])=None, stateNames:(str, List[str ------- """ - if(not stateIDs is None): - if(isinstance(stateIDs, int)): + if not stateIDs is None: + if isinstance(stateIDs, int): stateIDs = [stateIDs] for state in stateIDs: for atom in self.STATEATOMS: - if(state in atom.STATES): + if state in atom.STATES: del atom.STATES[state] del self.STATEIDENTIFIERS[state - 1] - self.STATEATOMHEADER = [x for x in self.STATEATOMHEADER if - (not x == "IAC" + str(state) and not "CHARGE" + str(state) == x)] + self.STATEATOMHEADER = [ + x for x in self.STATEATOMHEADER if (not x == "IAC" + str(state) and not "CHARGE" + str(state) == x) + ] - self.NPTB-=len(set(stateIDs)) + self.NPTB -= len(set(stateIDs)) - elif(not stateNames is None): - if(isinstance(stateNames, str)): + elif not stateNames is None: + if isinstance(stateNames, str): stateNames = [stateNames] for stateN in stateNames: - #print(stateN) - stateID = self.STATEIDENTIFIERS.index(stateN)+1 + # print(stateN) + stateID = self.STATEIDENTIFIERS.index(stateN) + 1 for atom in self.STATEATOMS: - if(stateID in atom.STATES): - del atom.STATES[stateID] - - del self.STATEIDENTIFIERS[stateID-1] - self.STATEATOMHEADER = [x for x in self.STATEATOMHEADER if( not x == "IAC"+str(stateID) and not "CHARGE"+str(stateID) == x)] + if stateID in atom.STATES: + del atom.STATES[stateID] + + del self.STATEIDENTIFIERS[stateID - 1] + self.STATEATOMHEADER = [ + x + for x in self.STATEATOMHEADER + if (not x == "IAC" + str(stateID) and not "CHARGE" + str(stateID) == x) + ] self.NPTB -= len(set(stateNames)) - elif(not stateNames is None and not stateIDs is None): + elif not stateNames is None and not stateIDs is None: raise Exception("Please give either stateNames or stateIDs") - def delete_atom(self, atomNR:(int, List[int])): + def delete_atom(self, atomNR: (int, List[int])): """ This function removes atom lines from the ptp file. @@ -339,13 +388,13 @@ def delete_atom(self, atomNR:(int, List[int])): atom to be removed. """ - if(isinstance(atomNR, int)): + if isinstance(atomNR, int): atomNR = [atomNR] ind_offset = 0 new_STATEATOMS = [] for ind, atom in enumerate(self.STATEATOMS): - if (atom.NR in atomNR): + if atom.NR in atomNR: continue else: new_STATEATOMS.append(atom) @@ -353,16 +402,16 @@ def delete_atom(self, atomNR:(int, List[int])): self.STATEATOMS = new_STATEATOMS self.NJLA -= len(atomNR) - """ STR FUNCTIONS """ + def _state_STATEATOMHEADER_str(self): - state_format_pattern = "{:>3} {:>5}"+"".join([" {:>3}{:>10}"for x in range(self.NPTB)])+" {:10} {:10}" + state_format_pattern = "{:>3} {:>5}" + "".join([" {:>3}{:>10}" for x in range(self.NPTB)]) + " {:10} {:10}" - if(len(self.STATEATOMHEADER) != self.NPTB*2+4): - tmp_list = " ".join(["CHARGE"+str(x)+" "+"IAC"+str(x) for x in range(self.NPTB)]) - self.STATEATOMHEADER = self.STATEATOMHEADER[:2]+tmp_list.split(" ")+self.STATEATOMHEADER[-2:] + if len(self.STATEATOMHEADER) != self.NPTB * 2 + 4: + tmp_list = " ".join(["CHARGE" + str(x) + " " + "IAC" + str(x) for x in range(self.NPTB)]) + self.STATEATOMHEADER = self.STATEATOMHEADER[:2] + tmp_list.split(" ") + self.STATEATOMHEADER[-2:] return state_format_pattern.format(*self.STATEATOMHEADER) @@ -371,35 +420,49 @@ def block_to_string(self) -> str: result += "# NJLA " + self.field_seperator + "NPTB" + self.line_seperator result += self.field_seperator + str(self.NJLA) + self.field_seperator + str(self.NPTB) + self.line_seperator result += "# state_identifiers" + self.line_seperator - result += self.field_seperator + self.field_seperator.join(map(str, self.STATEIDENTIFIERS)) + self.line_seperator + result += ( + self.field_seperator + self.field_seperator.join(map(str, self.STATEIDENTIFIERS)) + self.line_seperator + ) result += "# " + self._state_STATEATOMHEADER_str() + self.line_seperator result += "".join(map(str, sorted(self.STATEATOMS, key=lambda x: x.NR))) - result += "END"+self.line_seperator + result += "END" + self.line_seperator return result class PERTATOMPARAM(_generic_gromos_block): - def __init__(self, STATEATOMS:List[atom_lam_pertubation_state]=None, - STATEATOMHEADER: Tuple[str]= None, - NJLA: int=None, STATEIDENTIFIERS=None, - dummy_IAC = 22, dummy_CHARGE=0.0, content:List[str]=None): - + def __init__( + self, + STATEATOMS: List[atom_lam_pertubation_state] = None, + STATEATOMHEADER: Tuple[str] = None, + NJLA: int = None, + STATEIDENTIFIERS=None, + dummy_IAC=22, + dummy_CHARGE=0.0, + content: List[str] = None, + ): self.NPTB = 2 self.dummy_IAC = dummy_IAC self.dummy_CHARGE = dummy_CHARGE - if(content is None): - if(STATEATOMHEADER is None): - self.STATEATOMHEADER = ["NR", "RES", "NAME",] + if content is None: + if STATEATOMHEADER is None: + self.STATEATOMHEADER = [ + "NR", + "RES", + "NAME", + ] for s in range(self.NPTB): - self.STATEATOMHEADER += ["IAC", "MASS", "CHARGE",] + self.STATEATOMHEADER += [ + "IAC", + "MASS", + "CHARGE", + ] self.STATEATOMHEADER += ["ALPHLJ", "ALPHCRF"] else: self.STATEATOMHEADER = STATEATOMHEADER - - if(STATEATOMS is None): + if STATEATOMS is None: self.STATEATOMS = [] else: self.STATEATOMS = [] @@ -411,10 +474,17 @@ def __init__(self, STATEATOMS:List[atom_lam_pertubation_state]=None, super().__init__(used=True, name=__class__.__name__, content=content) # You can check yourself :) - if(not NJLA is None and not len(STATEATOMS)==NJLA): - raise ValueError("NJLA must be equal to the length of STATEATOMS! NJLA="+str(NJLA)+"\t stateatoms"+str(len(STATEATOMS))+"\n\n"+str(self)) - - def read_content_from_str(self, content:List[str]): + if not NJLA is None and not len(STATEATOMS) == NJLA: + raise ValueError( + "NJLA must be equal to the length of STATEATOMS! NJLA=" + + str(NJLA) + + "\t stateatoms" + + str(len(STATEATOMS)) + + "\n\n" + + str(self) + ) + + def read_content_from_str(self, content: List[str]): field = 0 NJLA = None STATEIDENTIFIERS = None @@ -423,33 +493,48 @@ def read_content_from_str(self, content:List[str]): first = True stdid = False for line in content: - if ("#" in line): + if "#" in line: comment = line - if("state_identifiers" in line): - stdid=True - elif(stdid): + if "state_identifiers" in line: + stdid = True + elif stdid: STATEIDENTIFIERS = line.replace("#", "").split() - stdid=False + stdid = False continue else: - if (field > 0): - if(first): - STATEATOMHEADER = ["NR", "RES", "NAME",] - [STATEATOMHEADER.extend(["IAC" + str(x), "MASS" + str(x), "CHARGE" + str(x)]) for x in range(1, 3)] + if field > 0: + if first: + STATEATOMHEADER = [ + "NR", + "RES", + "NAME", + ] + [ + STATEATOMHEADER.extend(["IAC" + str(x), "MASS" + str(x), "CHARGE" + str(x)]) + for x in range(1, 3) + ] STATEATOMHEADER += ["ALPHLJ", "ALPHCRF"] first = False state_line = {key: value for key, value in zip(STATEATOMHEADER, line.split())} - final_state_line = {key: state_line[key] for key in state_line if - (not "IAC" in key and not "CHARGE" in key and not "MASS" in key)} - states = {x: pertubation_lam_state_nonbonded(IAC=int(round(float(state_line["IAC" + str(x)]))), - MASS=float(state_line["MASS" + str(x)]), - CHARGE=float(state_line["CHARGE" + str(x)])) for x in range(1, 3)} + final_state_line = { + key: state_line[key] + for key in state_line + if (not "IAC" in key and not "CHARGE" in key and not "MASS" in key) + } + states = { + x: pertubation_lam_state_nonbonded( + IAC=int(round(float(state_line["IAC" + str(x)]))), + MASS=float(state_line["MASS" + str(x)]), + CHARGE=float(state_line["CHARGE" + str(x)]), + ) + for x in range(1, 3) + } - final_state_line.update({"STATES":states}) + final_state_line.update({"STATES": states}) STATEATOMS.append(atom_lam_pertubation_state(**final_state_line)) - elif (field == 0): + elif field == 0: NJLA = int(line.strip()) field += 1 @@ -459,20 +544,26 @@ def read_content_from_str(self, content:List[str]): self.STATEATOMS = STATEATOMS @property - def nStates(self)->int: + def nStates(self) -> int: return self.NPTB @property - def nTotalStateAtoms(self)->int: + def nTotalStateAtoms(self) -> int: return self.NJLA @property - def states(self)->dict: - return {self.STATEIDENTIFIERS[state-1]: {atom.NR: atom.STATES[state] for atom in sorted(self.STATEATOMS, key=lambda x: x.NR)} for state in range(1, self.NPTB+1)} + def states(self) -> dict: + return { + self.STATEIDENTIFIERS[state - 1]: { + atom.NR: atom.STATES[state] for atom in sorted(self.STATEATOMS, key=lambda x: x.NR) + } + for state in range(1, self.NPTB + 1) + } """ ADD FUNCTIONS """ + def add_state_atoms(self, state_atoms: List[atom_lam_pertubation_state]): """ This function can add states and atoms, but also overwrite state values of existing atoms. @@ -486,74 +577,75 @@ def add_state_atoms(self, state_atoms: List[atom_lam_pertubation_state]): """ - #some preperations: - pre_dummy_state = lambda atomMass: pertubation_lam_state_nonbonded(IAC=self.dummy_IAC, MASS=atomMass, CHARGE=self.dummy_CHARGE) + # some preperations: + pre_dummy_state = lambda atomMass: pertubation_lam_state_nonbonded( + IAC=self.dummy_IAC, MASS=atomMass, CHARGE=self.dummy_CHARGE + ) insert_id = self.STATEATOMHEADER.index("ALPHLJ") - #find all new states + # find all new states keys = np.array([list(natom.STATES.keys()) for natom in state_atoms], ndmin=1) unique_stateIDs = np.unique(np.concatenate(keys)) ## Todo: not urgent; state number adaptation ( present states 1,2,3,4 new state 8 - id should be 5 not 8) - unique_states = list(map(str, [ "state"+str(x) if isinstance(x, Number) else x for x in unique_stateIDs])) + unique_states = list(map(str, ["state" + str(x) if isinstance(x, Number) else x for x in unique_stateIDs])) - #insert new state IDs + # insert new state IDs off = 0 for unique_state in unique_stateIDs: - self.STATEATOMHEADER.insert(insert_id+off, "IAC"+str(unique_state)) - self.STATEATOMHEADER.insert(insert_id+off+1, "mass"+str(unique_state)) - self.STATEATOMHEADER.insert(insert_id+off+2, "CHARGE"+str(unique_state)) - off+=3 + self.STATEATOMHEADER.insert(insert_id + off, "IAC" + str(unique_state)) + self.STATEATOMHEADER.insert(insert_id + off + 1, "mass" + str(unique_state)) + self.STATEATOMHEADER.insert(insert_id + off + 2, "CHARGE" + str(unique_state)) + off += 3 - #add new state names - if(hasattr(self, "STATEIDENTIFIERS")): + # add new state names + if hasattr(self, "STATEIDENTIFIERS"): self.STATEIDENTIFIERS.extend(unique_states) self.NPTB += len(unique_states) else: self.STATEIDENTIFIERS = unique_states self.NPTB = len(unique_states) - #increase the number of new states + # increase the number of new states - - #1. Update already present atoms: + # 1. Update already present atoms: atomIDs = [atom.NR for atom in state_atoms] for atom in self.STATEATOMS: atom.STATES.update({key: val for key, val in atom.STATES.items()}) - possible_masses = [val.MASS for key, val in atom.STATES.items() if(val.MASS >0)] + possible_masses = [val.MASS for key, val in atom.STATES.items() if (val.MASS > 0)] dummy_state = pre_dummy_state(atomMass=possible_masses[0]) - if(atom.NR in atomIDs): + if atom.NR in atomIDs: new_atom = state_atoms[atomIDs.index(atom.NR)] atom.NAME = new_atom.NAME atom.STATES.update({key: val for key, val in new_atom.STATES.items()}) - possible_masses = [val.MASS for key, val in new_atom.STATES.items() if(val.MASS >0)] - #add missing dummies - #print(unique_stateIDs) + possible_masses = [val.MASS for key, val in new_atom.STATES.items() if (val.MASS > 0)] + # add missing dummies + # print(unique_stateIDs) atom.STATES.update({key: dummy_state for key in unique_stateIDs if not key in atom.STATES}) - #remove present atom + # remove present atom del atomIDs[atomIDs.index(atom.NR)] else: - #add missing dummies + # add missing dummies atom.STATES.update({key: dummy_state for key in unique_stateIDs if not key in atom.STATES}) - - #2. add new atoms + # 2. add new atoms new_atoms = [atom for atom in state_atoms if (atom.NR in atomIDs)] for atom in new_atoms: atom.STATES.update({key: val for key, val in atom.STATES.items()}) - possible_masses = [val.MASS for key, val in atom.STATES.items() if(val.MASS >0)] + possible_masses = [val.MASS for key, val in atom.STATES.items() if (val.MASS > 0)] dummy_state = pre_dummy_state(atomMass=possible_masses[0]) - atom.STATES.update({key:dummy_state for key in range(1, self.NPTB+1) if (key not in atom.STATES)}) + atom.STATES.update({key: dummy_state for key in range(1, self.NPTB + 1) if (key not in atom.STATES)}) self.STATEATOMS.append(atom) - self.NJLA +=1 + self.NJLA += 1 """ DELETING FUNCTIONS """ - def delete_state(self, stateIDs:(int, List[int])=None, stateNames:(str, List[str])=None): + + def delete_state(self, stateIDs: (int, List[int]) = None, stateNames: (str, List[str]) = None): """ This function deletes an state column. @@ -566,40 +658,45 @@ def delete_state(self, stateIDs:(int, List[int])=None, stateNames:(str, List[str ------- """ - if(not stateIDs is None): - if(isinstance(stateIDs, int)): + if not stateIDs is None: + if isinstance(stateIDs, int): stateIDs = [stateIDs] for state in stateIDs: for atom in self.STATEATOMS: - if(state in atom.STATES): + if state in atom.STATES: del atom.STATES[state] del self.STATEIDENTIFIERS[state - 1] - self.STATEATOMHEADER = [x for x in self.STATEATOMHEADER if - (not x == "IAC" + str(state) and not "CHARGE" + str(state) == x)] + self.STATEATOMHEADER = [ + x for x in self.STATEATOMHEADER if (not x == "IAC" + str(state) and not "CHARGE" + str(state) == x) + ] - self.NPTB-=len(set(stateIDs)) + self.NPTB -= len(set(stateIDs)) - elif(not stateNames is None): - if(isinstance(stateNames, str)): + elif not stateNames is None: + if isinstance(stateNames, str): stateNames = [stateNames] for stateN in stateNames: - #print(stateN) - stateID = self.STATEIDENTIFIERS.index(stateN)+1 + # print(stateN) + stateID = self.STATEIDENTIFIERS.index(stateN) + 1 for atom in self.STATEATOMS: - if(stateID in atom.STATES): - del atom.STATES[stateID] - - del self.STATEIDENTIFIERS[stateID-1] - self.STATEATOMHEADER = [x for x in self.STATEATOMHEADER if( not x == "IAC"+str(stateID) and not "CHARGE"+str(stateID) == x)] + if stateID in atom.STATES: + del atom.STATES[stateID] + + del self.STATEIDENTIFIERS[stateID - 1] + self.STATEATOMHEADER = [ + x + for x in self.STATEATOMHEADER + if (not x == "IAC" + str(stateID) and not "CHARGE" + str(stateID) == x) + ] self.NPTB -= len(set(stateNames)) - elif(not stateNames is None and not stateIDs is None): + elif not stateNames is None and not stateIDs is None: raise Exception("Please give either stateNames or stateIDs") - def delete_atom(self, atomNR:(int, List[int])): + def delete_atom(self, atomNR: (int, List[int])): """ This function removes atom lines from the ptp file. @@ -609,13 +706,13 @@ def delete_atom(self, atomNR:(int, List[int])): atom to be removed. """ - if(isinstance(atomNR, int)): + if isinstance(atomNR, int): atomNR = [atomNR] ind_offset = 0 new_STATEATOMS = [] for ind, atom in enumerate(self.STATEATOMS): - if (atom.NR in atomNR): + if atom.NR in atomNR: continue else: new_STATEATOMS.append(atom) @@ -623,71 +720,102 @@ def delete_atom(self, atomNR:(int, List[int])): self.STATEATOMS = new_STATEATOMS self.NJLA -= len(atomNR) - """ STR FUNCTIONS """ + def _state_STATEATOMHEADER_str(self): - state_format_pattern = "{:>5} {:>5} {:>5}"+"".join([" {:>5}{:>5}{:>10}"for x in range(self.NPTB)])+" {:10} {:10}" + state_format_pattern = ( + "{:>5} {:>5} {:>5}" + "".join([" {:>5}{:>5}{:>10}" for x in range(self.NPTB)]) + " {:10} {:10}" + ) return state_format_pattern.format(*self.STATEATOMHEADER) def block_to_string(self) -> str: result = self.name + self.line_seperator - result += "# NJLA " + self.field_seperator + "NPTB = " + self.field_seperator + str(self.NPTB) + self.field_seperator+ self.line_seperator - result += self.field_seperator + str(self.NJLA)+self.line_seperator + result += ( + "# NJLA " + + self.field_seperator + + "NPTB = " + + self.field_seperator + + str(self.NPTB) + + self.field_seperator + + self.line_seperator + ) + result += self.field_seperator + str(self.NJLA) + self.line_seperator result += "# state_identifiers" + self.line_seperator - result += "# "+self.field_seperator + self.field_seperator.join(map(str, self.STATEIDENTIFIERS)) + self.line_seperator + result += ( + "# " + + self.field_seperator + + self.field_seperator.join(map(str, self.STATEIDENTIFIERS)) + + self.line_seperator + ) result += "# " + self._state_STATEATOMHEADER_str() + self.line_seperator result += "".join(map(str, sorted(self.STATEATOMS, key=lambda x: x.NR))) - result += "END"+self.line_seperator + result += "END" + self.line_seperator return result + ### BONDED + class PERTBONDSTRETCH(_generic_gromos_block): - def __init__(self, STATEATOMS:List[atom_lam_pertubation_state_bond]=None, - STATEATOMHEADER: Tuple[str]= None, - NPB: int=None, - dummy_BOND = 22, content:List[str]=None): + def __init__( + self, + STATEATOMS: List[atom_lam_pertubation_state_bond] = None, + STATEATOMHEADER: Tuple[str] = None, + NPB: int = None, + dummy_BOND=22, + content: List[str] = None, + ): self.NPTB = 2 self.dummy_BOND = dummy_BOND - if(content is None): - if(STATEATOMHEADER is None): + if content is None: + if STATEATOMHEADER is None: self.STATEATOMHEADER = ["atomI", "atomJ", "type1", "type2"] else: self.STATEATOMHEADER = STATEATOMHEADER - - if(STATEATOMS is None): + if STATEATOMS is None: self.STATEATOMS = [] else: self.STATEATOMS = [] self.NPB = 0 - #self.add_state_atoms(STATEATOMS) + # self.add_state_atoms(STATEATOMS) super().__init__(used=True, name=__class__.__name__) else: super().__init__(used=True, name=__class__.__name__, content=content) # You can check yourself :) - if(not NPB is None and not len(STATEATOMS)==NPB): - raise ValueError("NJLA must be equal to the length of STATEATOMS! NJLA="+str(NPB)+"\t stateatoms"+str(len(STATEATOMS))+"\n\n"+str(self)) + if not NPB is None and not len(STATEATOMS) == NPB: + raise ValueError( + "NJLA must be equal to the length of STATEATOMS! NJLA=" + + str(NPB) + + "\t stateatoms" + + str(len(STATEATOMS)) + + "\n\n" + + str(self) + ) @property - def nStates(self)->int: + def nStates(self) -> int: return self.NPTB @property - def nTotalStateAtoms(self)->int: + def nTotalStateAtoms(self) -> int: return self.NPB @property - def states(self)->dict: - return {self.STATEIDENTIFIERS[state-1]: {atom.NR: atom.STATES[state] for atom in sorted(self.STATEATOMS, key=lambda x: x.NR)} for state in range(1, self.NPTB+1)} - - - def read_content_from_str(self, content:List[str]): + def states(self) -> dict: + return { + self.STATEIDENTIFIERS[state - 1]: { + atom.NR: atom.STATES[state] for atom in sorted(self.STATEATOMS, key=lambda x: x.NR) + } + for state in range(1, self.NPTB + 1) + } + + def read_content_from_str(self, content: List[str]): field = 0 NPB = None STATEIDENTIFIERS = None @@ -695,33 +823,32 @@ def read_content_from_str(self, content:List[str]): STATEATOMS = [] first = True stdid = False - i=1 + i = 1 for line in content: - if ("#" in line): + if "#" in line: comment = line - if("state_identifiers" in line): - stdid=True - elif(stdid): + if "state_identifiers" in line: + stdid = True + elif stdid: STATEIDENTIFIERS = line.replace("#", "").split() - stdid=False + stdid = False continue else: - if (field > 0): - if(first): - STATEATOMHEADER = ["atomI", "atomJ", "type1", "type2"] + if field > 0: + if first: + STATEATOMHEADER = ["atomI", "atomJ", "type1", "type2"] first = False state_line = {key: value for key, value in zip(STATEATOMHEADER, line.split())} - state_line.update({"NR":len(STATEATOMS)+1}) + state_line.update({"NR": len(STATEATOMS) + 1}) final_state_line = {key: state_line[key] for key in state_line if (not "type" in key)} - states = {1: state_line["type1"], - 2: state_line["type2"]} + states = {1: state_line["type1"], 2: state_line["type2"]} - final_state_line.update({"STATES":states}) + final_state_line.update({"STATES": states}) STATEATOMS.append(atom_lam_pertubation_state_bond(**final_state_line)) - elif (field == 0): + elif field == 0: NPB = int(line.strip()) field += 1 @@ -733,64 +860,87 @@ def read_content_from_str(self, content:List[str]): """ STR FUNCTIONS """ + def _state_STATEATOMHEADER_str(self): - state_format_pattern = "{:>5} {:>5}"+"".join([" {:>5} "for x in range(self.NPTB)])+"" + state_format_pattern = "{:>5} {:>5}" + "".join([" {:>5} " for x in range(self.NPTB)]) + "" return state_format_pattern.format(*self.STATEATOMHEADER) def block_to_string(self) -> str: result = self.name + self.line_seperator - result += "# NPB " + self.field_seperator + "NPTB = " + self.field_seperator + str(self.NPTB) + self.field_seperator+ self.line_seperator - result += self.field_seperator + str(self.NPB)+self.line_seperator + result += ( + "# NPB " + + self.field_seperator + + "NPTB = " + + self.field_seperator + + str(self.NPTB) + + self.field_seperator + + self.line_seperator + ) + result += self.field_seperator + str(self.NPB) + self.line_seperator result += "# " + self._state_STATEATOMHEADER_str() + self.line_seperator result += "".join(map(str, sorted(self.STATEATOMS, key=lambda x: x.NR))) - result += "END"+self.line_seperator + result += "END" + self.line_seperator return result class PERTBONDSTRETCHH(_generic_gromos_block): - def __init__(self, STATEATOMS:List[atom_lam_pertubation_state_bond]=None, - STATEATOMHEADER: Tuple[str]= None, - NPB: int=None, - dummy_BOND = 22, content:List[str]=None): + def __init__( + self, + STATEATOMS: List[atom_lam_pertubation_state_bond] = None, + STATEATOMHEADER: Tuple[str] = None, + NPB: int = None, + dummy_BOND=22, + content: List[str] = None, + ): self.NPTB = 2 self.dummy_BOND = dummy_BOND - if(content is None): - if(STATEATOMHEADER is None): + if content is None: + if STATEATOMHEADER is None: self.STATEATOMHEADER = ["atomI", "atomJ", "type1", "type2"] else: self.STATEATOMHEADER = STATEATOMHEADER - - if(STATEATOMS is None): + if STATEATOMS is None: self.STATEATOMS = [] else: self.STATEATOMS = [] self.NPB = 0 - #self.add_state_atoms(STATEATOMS) + # self.add_state_atoms(STATEATOMS) super().__init__(used=True, name=__class__.__name__) else: super().__init__(used=True, name=__class__.__name__, content=content) # You can check yourself :) - if(not NPB is None and not len(STATEATOMS)==NPB): - raise ValueError("NJLA must be equal to the length of STATEATOMS! NJLA="+str(NPB)+"\t stateatoms"+str(len(STATEATOMS))+"\n\n"+str(self)) + if not NPB is None and not len(STATEATOMS) == NPB: + raise ValueError( + "NJLA must be equal to the length of STATEATOMS! NJLA=" + + str(NPB) + + "\t stateatoms" + + str(len(STATEATOMS)) + + "\n\n" + + str(self) + ) @property - def nStates(self)->int: + def nStates(self) -> int: return self.NPTB @property - def nTotalStateAtoms(self)->int: + def nTotalStateAtoms(self) -> int: return self.NPB @property - def states(self)->dict: - return {self.STATEIDENTIFIERS[state-1]: {atom.NR: atom.STATES[state] for atom in sorted(self.STATEATOMS, key=lambda x: x.NR)} for state in range(1, self.NPTB+1)} - - - def read_content_from_str(self, content:List[str]): + def states(self) -> dict: + return { + self.STATEIDENTIFIERS[state - 1]: { + atom.NR: atom.STATES[state] for atom in sorted(self.STATEATOMS, key=lambda x: x.NR) + } + for state in range(1, self.NPTB + 1) + } + + def read_content_from_str(self, content: List[str]): field = 0 NPB = None STATEIDENTIFIERS = None @@ -798,33 +948,32 @@ def read_content_from_str(self, content:List[str]): STATEATOMS = [] first = True stdid = False - i=1 + i = 1 for line in content: - if ("#" in line): + if "#" in line: comment = line - if("state_identifiers" in line): - stdid=True - elif(stdid): + if "state_identifiers" in line: + stdid = True + elif stdid: STATEIDENTIFIERS = line.replace("#", "").split() - stdid=False + stdid = False continue else: - if (field > 0): - if(first): - STATEATOMHEADER = ["atomI", "atomJ", "type1", "type2"] + if field > 0: + if first: + STATEATOMHEADER = ["atomI", "atomJ", "type1", "type2"] first = False state_line = {key: value for key, value in zip(STATEATOMHEADER, line.split())} - state_line.update({"NR":len(STATEATOMS)+1}) + state_line.update({"NR": len(STATEATOMS) + 1}) final_state_line = {key: state_line[key] for key in state_line if (not "type" in key)} - states = {1: state_line["type1"], - 2: state_line["type2"]} + states = {1: state_line["type1"], 2: state_line["type2"]} - final_state_line.update({"STATES":states}) + final_state_line.update({"STATES": states}) STATEATOMS.append(atom_lam_pertubation_state_bond(**final_state_line)) - elif (field == 0): + elif field == 0: NPB = int(line.strip()) field += 1 @@ -836,65 +985,90 @@ def read_content_from_str(self, content:List[str]): """ STR FUNCTIONS """ + def _state_STATEATOMHEADER_str(self): - state_format_pattern = "{:>5} {:>5}"+"".join([" {:>5} "for x in range(self.NPTB)])+"" + state_format_pattern = "{:>5} {:>5}" + "".join([" {:>5} " for x in range(self.NPTB)]) + "" return state_format_pattern.format(*self.STATEATOMHEADER) def block_to_string(self) -> str: result = self.name + self.line_seperator - result += "# NPB " + self.field_seperator + "NPTB = " + self.field_seperator + str(self.NPTB) + self.field_seperator+ self.line_seperator - result += self.field_seperator + str(self.NPB)+self.line_seperator + result += ( + "# NPB " + + self.field_seperator + + "NPTB = " + + self.field_seperator + + str(self.NPTB) + + self.field_seperator + + self.line_seperator + ) + result += self.field_seperator + str(self.NPB) + self.line_seperator result += "# " + self._state_STATEATOMHEADER_str() + self.line_seperator result += "".join(map(str, sorted(self.STATEATOMS, key=lambda x: x.NR))) - result += "END"+self.line_seperator + result += "END" + self.line_seperator return result + ### ANGLE + class PERTBONDANGLE(_generic_gromos_block): - def __init__(self, STATEATOMS:List[atom_lam_pertubation_state_angle]=None, - STATEATOMHEADER: Tuple[str]= None, - NPA: int=None, - dummy_ANGLE = 22, content:List[str]=None): + def __init__( + self, + STATEATOMS: List[atom_lam_pertubation_state_angle] = None, + STATEATOMHEADER: Tuple[str] = None, + NPA: int = None, + dummy_ANGLE=22, + content: List[str] = None, + ): self.NPTB = 2 self.dummy_ANGLE = dummy_ANGLE - if(content is None): - if(STATEATOMHEADER is None): + if content is None: + if STATEATOMHEADER is None: self.STATEATOMHEADER = ["atomI", "atomJ", "atomK", "type1", "type2"] else: self.STATEATOMHEADER = STATEATOMHEADER - - if(STATEATOMS is None): + if STATEATOMS is None: self.STATEATOMS = [] else: self.STATEATOMS = [] self.NPA = 0 - #self.add_state_atoms(STATEATOMS) + # self.add_state_atoms(STATEATOMS) super().__init__(used=True, name=__class__.__name__) else: super().__init__(used=True, name=__class__.__name__, content=content) # You can check yourself :) - if(not NPA is None and not len(STATEATOMS)==NPA): - raise ValueError("NJLA must be equal to the length of STATEATOMS! NJLA="+str(NPA)+"\t stateatoms"+str(len(STATEATOMS))+"\n\n"+str(self)) + if not NPA is None and not len(STATEATOMS) == NPA: + raise ValueError( + "NJLA must be equal to the length of STATEATOMS! NJLA=" + + str(NPA) + + "\t stateatoms" + + str(len(STATEATOMS)) + + "\n\n" + + str(self) + ) @property - def nStates(self)->int: + def nStates(self) -> int: return self.NPTB @property - def nTotalStateAtoms(self)->int: + def nTotalStateAtoms(self) -> int: return self.NPA @property - def states(self)->dict: - return {self.STATEIDENTIFIERS[state-1]: {atom.NR: atom.STATES[state] for atom in sorted(self.STATEATOMS, key=lambda x: x.NR)} for state in range(1, self.NPTB+1)} - - - def read_content_from_str(self, content:List[str]): + def states(self) -> dict: + return { + self.STATEIDENTIFIERS[state - 1]: { + atom.NR: atom.STATES[state] for atom in sorted(self.STATEATOMS, key=lambda x: x.NR) + } + for state in range(1, self.NPTB + 1) + } + + def read_content_from_str(self, content: List[str]): field = 0 NPA = None STATEIDENTIFIERS = None @@ -902,33 +1076,32 @@ def read_content_from_str(self, content:List[str]): STATEATOMS = [] first = True stdid = False - i=1 + i = 1 for line in content: - if ("#" in line): + if "#" in line: comment = line - if("state_identifiers" in line): - stdid=True - elif(stdid): + if "state_identifiers" in line: + stdid = True + elif stdid: STATEIDENTIFIERS = line.replace("#", "").split() - stdid=False + stdid = False continue else: - if (field > 0): - if(first): - STATEATOMHEADER = ["atomI", "atomJ", "atomK", "type1", "type2"] + if field > 0: + if first: + STATEATOMHEADER = ["atomI", "atomJ", "atomK", "type1", "type2"] first = False state_line = {key: value for key, value in zip(STATEATOMHEADER, line.split())} - state_line.update({"NR":len(STATEATOMS)+1}) + state_line.update({"NR": len(STATEATOMS) + 1}) final_state_line = {key: state_line[key] for key in state_line if (not "type" in key)} - states = {1: state_line["type1"], - 2: state_line["type2"]} + states = {1: state_line["type1"], 2: state_line["type2"]} - final_state_line.update({"STATES":states}) + final_state_line.update({"STATES": states}) STATEATOMS.append(atom_lam_pertubation_state_angle(**final_state_line)) - elif (field == 0): + elif field == 0: NPA = int(line.strip()) field += 1 @@ -940,64 +1113,87 @@ def read_content_from_str(self, content:List[str]): """ STR FUNCTIONS """ + def _state_STATEATOMHEADER_str(self): - state_format_pattern = "{:>5} {:>5} {:>5}"+"".join([" {:>5} "for x in range(self.NPTB)])+"" + state_format_pattern = "{:>5} {:>5} {:>5}" + "".join([" {:>5} " for x in range(self.NPTB)]) + "" return state_format_pattern.format(*self.STATEATOMHEADER) def block_to_string(self) -> str: result = self.name + self.line_seperator - result += "# NPA " + self.field_seperator + "NPTB = " + self.field_seperator + str(self.NPTB) + self.field_seperator+ self.line_seperator - result += self.field_seperator + str(self.NPA)+self.line_seperator + result += ( + "# NPA " + + self.field_seperator + + "NPTB = " + + self.field_seperator + + str(self.NPTB) + + self.field_seperator + + self.line_seperator + ) + result += self.field_seperator + str(self.NPA) + self.line_seperator result += "# " + self._state_STATEATOMHEADER_str() + self.line_seperator result += "".join(map(str, sorted(self.STATEATOMS, key=lambda x: x.NR))) - result += "END"+self.line_seperator + result += "END" + self.line_seperator return result class PERTBONDANGLEH(_generic_gromos_block): - def __init__(self, STATEATOMS:List[atom_lam_pertubation_state_angle]=None, - STATEATOMHEADER: Tuple[str]= None, - NPA: int=None, - dummy_ANGLE = 22, content:List[str]=None): + def __init__( + self, + STATEATOMS: List[atom_lam_pertubation_state_angle] = None, + STATEATOMHEADER: Tuple[str] = None, + NPA: int = None, + dummy_ANGLE=22, + content: List[str] = None, + ): self.NPTB = 2 self.dummy_ANGLE = dummy_ANGLE - if(content is None): - if(STATEATOMHEADER is None): + if content is None: + if STATEATOMHEADER is None: self.STATEATOMHEADER = ["atomI", "atomJ", "atomK", "type1", "type2"] else: self.STATEATOMHEADER = STATEATOMHEADER - - if(STATEATOMS is None): + if STATEATOMS is None: self.STATEATOMS = [] else: self.STATEATOMS = [] self.NPA = 0 - #self.add_state_atoms(STATEATOMS) + # self.add_state_atoms(STATEATOMS) super().__init__(used=True, name=__class__.__name__) else: super().__init__(used=True, name=__class__.__name__, content=content) # You can check yourself :) - if(not NPA is None and not len(STATEATOMS)==NPA): - raise ValueError("NJLA must be equal to the length of STATEATOMS! NJLA="+str(NPA)+"\t stateatoms"+str(len(STATEATOMS))+"\n\n"+str(self)) + if not NPA is None and not len(STATEATOMS) == NPA: + raise ValueError( + "NJLA must be equal to the length of STATEATOMS! NJLA=" + + str(NPA) + + "\t stateatoms" + + str(len(STATEATOMS)) + + "\n\n" + + str(self) + ) @property - def nStates(self)->int: + def nStates(self) -> int: return self.NPTB @property - def nTotalStateAtoms(self)->int: + def nTotalStateAtoms(self) -> int: return self.NPA @property - def states(self)->dict: - return {self.STATEIDENTIFIERS[state-1]: {atom.NR: atom.STATES[state] for atom in sorted(self.STATEATOMS, key=lambda x: x.NR)} for state in range(1, self.NPTB+1)} - - - def read_content_from_str(self, content:List[str]): + def states(self) -> dict: + return { + self.STATEIDENTIFIERS[state - 1]: { + atom.NR: atom.STATES[state] for atom in sorted(self.STATEATOMS, key=lambda x: x.NR) + } + for state in range(1, self.NPTB + 1) + } + + def read_content_from_str(self, content: List[str]): field = 0 NPA = None STATEIDENTIFIERS = None @@ -1005,33 +1201,32 @@ def read_content_from_str(self, content:List[str]): STATEATOMS = [] first = True stdid = False - i=1 + i = 1 for line in content: - if ("#" in line): + if "#" in line: comment = line - if("state_identifiers" in line): - stdid=True - elif(stdid): + if "state_identifiers" in line: + stdid = True + elif stdid: STATEIDENTIFIERS = line.replace("#", "").split() - stdid=False + stdid = False continue else: - if (field > 0): - if(first): - STATEATOMHEADER = ["atomI", "atomJ", "atomK", "type1", "type2"] + if field > 0: + if first: + STATEATOMHEADER = ["atomI", "atomJ", "atomK", "type1", "type2"] first = False state_line = {key: value for key, value in zip(STATEATOMHEADER, line.split())} - state_line.update({"NR":len(STATEATOMS)+1}) + state_line.update({"NR": len(STATEATOMS) + 1}) final_state_line = {key: state_line[key] for key in state_line if (not "type" in key)} - states = {1: state_line["type1"], - 2: state_line["type2"]} + states = {1: state_line["type1"], 2: state_line["type2"]} - final_state_line.update({"STATES":states}) + final_state_line.update({"STATES": states}) STATEATOMS.append(atom_lam_pertubation_state_angle(**final_state_line)) - elif (field == 0): + elif field == 0: NPA = int(line.strip()) field += 1 @@ -1043,65 +1238,90 @@ def read_content_from_str(self, content:List[str]): """ STR FUNCTIONS """ + def _state_STATEATOMHEADER_str(self): - state_format_pattern = "{:>5} {:>5} {:>5}"+"".join([" {:>5} "for x in range(self.NPTB)])+"" + state_format_pattern = "{:>5} {:>5} {:>5}" + "".join([" {:>5} " for x in range(self.NPTB)]) + "" return state_format_pattern.format(*self.STATEATOMHEADER) def block_to_string(self) -> str: result = self.name + self.line_seperator - result += "# NPA " + self.field_seperator + "NPTB = " + self.field_seperator + str(self.NPTB) + self.field_seperator+ self.line_seperator - result += self.field_seperator + str(self.NPA)+self.line_seperator + result += ( + "# NPA " + + self.field_seperator + + "NPTB = " + + self.field_seperator + + str(self.NPTB) + + self.field_seperator + + self.line_seperator + ) + result += self.field_seperator + str(self.NPA) + self.line_seperator result += "# " + self._state_STATEATOMHEADER_str() + self.line_seperator result += "".join(map(str, sorted(self.STATEATOMS, key=lambda x: x.NR))) - result += "END"+self.line_seperator + result += "END" + self.line_seperator return result + ### DIHEDRAL + class PERTPROPERDIH(_generic_gromos_block): - def __init__(self, STATEATOMS:List[atom_lam_pertubation_state_dihedral]=None, - STATEATOMHEADER: Tuple[str]= None, - NPD: int=None, - dummy_DIH = 22, content:List[str]=None): + def __init__( + self, + STATEATOMS: List[atom_lam_pertubation_state_dihedral] = None, + STATEATOMHEADER: Tuple[str] = None, + NPD: int = None, + dummy_DIH=22, + content: List[str] = None, + ): self.NPTB = 2 self.dummy_DIH = dummy_DIH - if(content is None): - if(STATEATOMHEADER is None): + if content is None: + if STATEATOMHEADER is None: self.STATEATOMHEADER = ["atomI", "atomJ", "atomK", "atomL", "type1", "type2"] else: self.STATEATOMHEADER = STATEATOMHEADER - - if(STATEATOMS is None): + if STATEATOMS is None: self.STATEATOMS = [] else: self.STATEATOMS = [] self.NPD = 0 - #self.add_state_atoms(STATEATOMS) + # self.add_state_atoms(STATEATOMS) super().__init__(used=True, name=__class__.__name__) else: super().__init__(used=True, name=__class__.__name__, content=content) # You can check yourself :) - if(not NPD is None and not len(STATEATOMS)==NPD): - raise ValueError("NJLA must be equal to the length of STATEATOMS! NJLA="+str(NPD)+"\t stateatoms"+str(len(STATEATOMS))+"\n\n"+str(self)) + if not NPD is None and not len(STATEATOMS) == NPD: + raise ValueError( + "NJLA must be equal to the length of STATEATOMS! NJLA=" + + str(NPD) + + "\t stateatoms" + + str(len(STATEATOMS)) + + "\n\n" + + str(self) + ) @property - def nStates(self)->int: + def nStates(self) -> int: return self.NPTB @property - def nTotalStateAtoms(self)->int: + def nTotalStateAtoms(self) -> int: return self.NPD @property - def states(self)->dict: - return {self.STATEIDENTIFIERS[state-1]: {atom.NR: atom.STATES[state] for atom in sorted(self.STATEATOMS, key=lambda x: x.NR)} for state in range(1, self.NPTB+1)} - - - def read_content_from_str(self, content:List[str]): + def states(self) -> dict: + return { + self.STATEIDENTIFIERS[state - 1]: { + atom.NR: atom.STATES[state] for atom in sorted(self.STATEATOMS, key=lambda x: x.NR) + } + for state in range(1, self.NPTB + 1) + } + + def read_content_from_str(self, content: List[str]): field = 0 NPD = None STATEIDENTIFIERS = None @@ -1109,33 +1329,32 @@ def read_content_from_str(self, content:List[str]): STATEATOMS = [] first = True stdid = False - i=1 + i = 1 for line in content: - if ("#" in line): + if "#" in line: comment = line - if("state_identifiers" in line): - stdid=True - elif(stdid): + if "state_identifiers" in line: + stdid = True + elif stdid: STATEIDENTIFIERS = line.replace("#", "").split() - stdid=False + stdid = False continue else: - if (field > 0): - if(first): - STATEATOMHEADER = ["atomI", "atomJ", "atomK", "atomL", "type1", "type2"] + if field > 0: + if first: + STATEATOMHEADER = ["atomI", "atomJ", "atomK", "atomL", "type1", "type2"] first = False state_line = {key: value for key, value in zip(STATEATOMHEADER, line.split())} - state_line.update({"NR":len(STATEATOMS)+1}) + state_line.update({"NR": len(STATEATOMS) + 1}) final_state_line = {key: state_line[key] for key in state_line if (not "type" in key)} - states = {1: state_line["type1"], - 2: state_line["type2"]} + states = {1: state_line["type1"], 2: state_line["type2"]} - final_state_line.update({"STATES":states}) + final_state_line.update({"STATES": states}) STATEATOMS.append(atom_lam_pertubation_state_dihedral(**final_state_line)) - elif (field == 0): + elif field == 0: NPD = int(line.strip()) field += 1 @@ -1147,64 +1366,87 @@ def read_content_from_str(self, content:List[str]): """ STR FUNCTIONS """ + def _state_STATEATOMHEADER_str(self): - state_format_pattern = "{:>5} {:>5} {:>5} {:>5}"+"".join([" {:>5} "for x in range(self.NPTB)])+"" + state_format_pattern = "{:>5} {:>5} {:>5} {:>5}" + "".join([" {:>5} " for x in range(self.NPTB)]) + "" return state_format_pattern.format(*self.STATEATOMHEADER) def block_to_string(self) -> str: result = self.name + self.line_seperator - result += "# NPD " + self.field_seperator + "NPTB = " + self.field_seperator + str(self.NPTB) + self.field_seperator+ self.line_seperator - result += self.field_seperator + str(self.NPD)+self.line_seperator + result += ( + "# NPD " + + self.field_seperator + + "NPTB = " + + self.field_seperator + + str(self.NPTB) + + self.field_seperator + + self.line_seperator + ) + result += self.field_seperator + str(self.NPD) + self.line_seperator result += "# " + self._state_STATEATOMHEADER_str() + self.line_seperator result += "".join(map(str, sorted(self.STATEATOMS, key=lambda x: x.NR))) - result += "END"+self.line_seperator + result += "END" + self.line_seperator return result class PERTPROPERDIHH(_generic_gromos_block): - def __init__(self, STATEATOMS:List[atom_lam_pertubation_state_dihedral]=None, - STATEATOMHEADER: Tuple[str]= None, - NPD: int=None, - dummy_DIH = 22, content:List[str]=None): + def __init__( + self, + STATEATOMS: List[atom_lam_pertubation_state_dihedral] = None, + STATEATOMHEADER: Tuple[str] = None, + NPD: int = None, + dummy_DIH=22, + content: List[str] = None, + ): self.NPTB = 2 self.dummy_DIH = dummy_DIH - if(content is None): - if(STATEATOMHEADER is None): + if content is None: + if STATEATOMHEADER is None: self.STATEATOMHEADER = ["atomI", "atomJ", "atomK", "atomL", "type1", "type2"] else: self.STATEATOMHEADER = STATEATOMHEADER - - if(STATEATOMS is None): + if STATEATOMS is None: self.STATEATOMS = [] else: self.STATEATOMS = [] self.NPD = 0 - #self.add_state_atoms(STATEATOMS) + # self.add_state_atoms(STATEATOMS) super().__init__(used=True, name=__class__.__name__) else: super().__init__(used=True, name=__class__.__name__, content=content) # You can check yourself :) - if(not NPD is None and not len(STATEATOMS)==NPD): - raise ValueError("NJLA must be equal to the length of STATEATOMS! NJLA="+str(NPD)+"\t stateatoms"+str(len(STATEATOMS))+"\n\n"+str(self)) + if not NPD is None and not len(STATEATOMS) == NPD: + raise ValueError( + "NJLA must be equal to the length of STATEATOMS! NJLA=" + + str(NPD) + + "\t stateatoms" + + str(len(STATEATOMS)) + + "\n\n" + + str(self) + ) @property - def nStates(self)->int: + def nStates(self) -> int: return self.NPTB @property - def nTotalStateAtoms(self)->int: + def nTotalStateAtoms(self) -> int: return self.NPD @property - def states(self)->dict: - return {self.STATEIDENTIFIERS[state-1]: {atom.NR: atom.STATES[state] for atom in sorted(self.STATEATOMS, key=lambda x: x.NR)} for state in range(1, self.NPTB+1)} - - - def read_content_from_str(self, content:List[str]): + def states(self) -> dict: + return { + self.STATEIDENTIFIERS[state - 1]: { + atom.NR: atom.STATES[state] for atom in sorted(self.STATEATOMS, key=lambda x: x.NR) + } + for state in range(1, self.NPTB + 1) + } + + def read_content_from_str(self, content: List[str]): field = 0 NPD = None STATEIDENTIFIERS = None @@ -1212,33 +1454,32 @@ def read_content_from_str(self, content:List[str]): STATEATOMS = [] first = True stdid = False - i=1 + i = 1 for line in content: - if ("#" in line): + if "#" in line: comment = line - if("state_identifiers" in line): - stdid=True - elif(stdid): + if "state_identifiers" in line: + stdid = True + elif stdid: STATEIDENTIFIERS = line.replace("#", "").split() - stdid=False + stdid = False continue else: - if (field > 0): - if(first): - STATEATOMHEADER = ["atomI", "atomJ", "atomK", "atomL", "type1", "type2"] + if field > 0: + if first: + STATEATOMHEADER = ["atomI", "atomJ", "atomK", "atomL", "type1", "type2"] first = False state_line = {key: value for key, value in zip(STATEATOMHEADER, line.split())} - state_line.update({"NR":len(STATEATOMS)+1}) + state_line.update({"NR": len(STATEATOMS) + 1}) final_state_line = {key: state_line[key] for key in state_line if (not "type" in key)} - states = {1: state_line["type1"], - 2: state_line["type2"]} + states = {1: state_line["type1"], 2: state_line["type2"]} - final_state_line.update({"STATES":states}) + final_state_line.update({"STATES": states}) STATEATOMS.append(atom_lam_pertubation_state_dihedral(**final_state_line)) - elif (field == 0): + elif field == 0: NPD = int(line.strip()) field += 1 @@ -1250,34 +1491,47 @@ def read_content_from_str(self, content:List[str]): """ STR FUNCTIONS """ + def _state_STATEATOMHEADER_str(self): - state_format_pattern = "{:>5} {:>5} {:>5} {:>5}"+"".join([" {:>5} "for x in range(self.NPTB)])+"" + state_format_pattern = "{:>5} {:>5} {:>5} {:>5}" + "".join([" {:>5} " for x in range(self.NPTB)]) + "" return state_format_pattern.format(*self.STATEATOMHEADER) def block_to_string(self) -> str: result = self.name + self.line_seperator - result += "# NPD " + self.field_seperator + "NPTB = " + self.field_seperator + str(self.NPTB) + self.field_seperator+ self.line_seperator - result += self.field_seperator + str(self.NPD)+self.line_seperator + result += ( + "# NPD " + + self.field_seperator + + "NPTB = " + + self.field_seperator + + str(self.NPTB) + + self.field_seperator + + self.line_seperator + ) + result += self.field_seperator + str(self.NPD) + self.line_seperator result += "# " + self._state_STATEATOMHEADER_str() + self.line_seperator result += "".join(map(str, sorted(self.STATEATOMS, key=lambda x: x.NR))) - result += "END"+self.line_seperator + result += "END" + self.line_seperator return result class PERTPROPERDIH(_generic_gromos_block): - def __init__(self, STATEATOMS: List[atom_lam_pertubation_state_dihedral] = None, - STATEATOMHEADER: Tuple[str] = None, - NPD: int = None, - dummy_DIH=22, content: List[str] = None): + def __init__( + self, + STATEATOMS: List[atom_lam_pertubation_state_dihedral] = None, + STATEATOMHEADER: Tuple[str] = None, + NPD: int = None, + dummy_DIH=22, + content: List[str] = None, + ): self.NPTB = 2 self.dummy_DIH = dummy_DIH - if (content is None): - if (STATEATOMHEADER is None): + if content is None: + if STATEATOMHEADER is None: self.STATEATOMHEADER = ["atomI", "atomJ", "atomK", "atomL", "type1", "type2"] else: self.STATEATOMHEADER = STATEATOMHEADER - if (STATEATOMS is None): + if STATEATOMS is None: self.STATEATOMS = [] else: self.STATEATOMS = [] @@ -1289,10 +1543,15 @@ def __init__(self, STATEATOMS: List[atom_lam_pertubation_state_dihedral] = None, super().__init__(used=True, name=__class__.__name__, content=content) # You can check yourself :) - if (not NPD is None and not len(STATEATOMS) == NPD): + if not NPD is None and not len(STATEATOMS) == NPD: raise ValueError( - "NJLA must be equal to the length of STATEATOMS! NJLA=" + str(NPD) + "\t stateatoms" + str( - len(STATEATOMS)) + "\n\n" + str(self)) + "NJLA must be equal to the length of STATEATOMS! NJLA=" + + str(NPD) + + "\t stateatoms" + + str(len(STATEATOMS)) + + "\n\n" + + str(self) + ) @property def nStates(self) -> int: @@ -1304,9 +1563,12 @@ def nTotalStateAtoms(self) -> int: @property def states(self) -> dict: - return {self.STATEIDENTIFIERS[state - 1]: {atom.NR: atom.STATES[state] for atom in - sorted(self.STATEATOMS, key=lambda x: x.NR)} for state in - range(1, self.NPTB + 1)} + return { + self.STATEIDENTIFIERS[state - 1]: { + atom.NR: atom.STATES[state] for atom in sorted(self.STATEATOMS, key=lambda x: x.NR) + } + for state in range(1, self.NPTB + 1) + } def read_content_from_str(self, content: List[str]): field = 0 @@ -1318,17 +1580,17 @@ def read_content_from_str(self, content: List[str]): stdid = False i = 1 for line in content: - if ("#" in line): + if "#" in line: comment = line - if ("state_identifiers" in line): + if "state_identifiers" in line: stdid = True - elif (stdid): + elif stdid: STATEIDENTIFIERS = line.replace("#", "").split() stdid = False continue else: - if (field > 0): - if (first): + if field > 0: + if first: STATEATOMHEADER = ["atomI", "atomJ", "atomK", "atomL", "type1", "type2"] first = False @@ -1336,13 +1598,12 @@ def read_content_from_str(self, content: List[str]): state_line.update({"NR": len(STATEATOMS) + 1}) final_state_line = {key: state_line[key] for key in state_line if (not "type" in key)} - states = {1: state_line["type1"], - 2: state_line["type2"]} + states = {1: state_line["type1"], 2: state_line["type2"]} final_state_line.update({"STATES": states}) STATEATOMS.append(atom_lam_pertubation_state_dihedral(**final_state_line)) - elif (field == 0): + elif field == 0: NPD = int(line.strip()) field += 1 @@ -1361,60 +1622,83 @@ def _state_STATEATOMHEADER_str(self): def block_to_string(self) -> str: result = self.name + self.line_seperator - result += "# NPD " + self.field_seperator + "NPTB = " + self.field_seperator + str( - self.NPTB) + self.field_seperator + self.line_seperator + result += ( + "# NPD " + + self.field_seperator + + "NPTB = " + + self.field_seperator + + str(self.NPTB) + + self.field_seperator + + self.line_seperator + ) result += self.field_seperator + str(self.NPD) + self.line_seperator result += "# " + self._state_STATEATOMHEADER_str() + self.line_seperator result += "".join(map(str, sorted(self.STATEATOMS, key=lambda x: x.NR))) result += "END" + self.line_seperator return result + ### IMPROPER + class PERTIMROPERDIH(_generic_gromos_block): - def __init__(self, STATEATOMS:List[atom_lam_pertubation_state_dihedral]=None, - STATEATOMHEADER: Tuple[str]= None, - NPD: int=None, - dummy_IMP = 22, content:List[str]=None): + def __init__( + self, + STATEATOMS: List[atom_lam_pertubation_state_dihedral] = None, + STATEATOMHEADER: Tuple[str] = None, + NPD: int = None, + dummy_IMP=22, + content: List[str] = None, + ): self.NPTB = 2 self.dummy_DIH = dummy_IMP - if(content is None): - if(STATEATOMHEADER is None): + if content is None: + if STATEATOMHEADER is None: self.STATEATOMHEADER = ["atomI", "atomJ", "atomK", "atomL", "type1", "type2"] else: self.STATEATOMHEADER = STATEATOMHEADER - - if(STATEATOMS is None): + if STATEATOMS is None: self.STATEATOMS = [] else: self.STATEATOMS = [] self.NPD = 0 - #self.add_state_atoms(STATEATOMS) + # self.add_state_atoms(STATEATOMS) super().__init__(used=True, name=__class__.__name__) else: super().__init__(used=True, name=__class__.__name__, content=content) # You can check yourself :) - if(not NPD is None and not len(STATEATOMS)==NPD): - raise ValueError("NPD must be equal to the length of STATEATOMS! NPD="+str(NPD)+"\t stateatoms"+str(len(STATEATOMS))+"\n\n"+str(self)) + if not NPD is None and not len(STATEATOMS) == NPD: + raise ValueError( + "NPD must be equal to the length of STATEATOMS! NPD=" + + str(NPD) + + "\t stateatoms" + + str(len(STATEATOMS)) + + "\n\n" + + str(self) + ) @property - def nStates(self)->int: + def nStates(self) -> int: return self.NPTB @property - def nTotalStateAtoms(self)->int: + def nTotalStateAtoms(self) -> int: return self.NPD @property - def states(self)->dict: - return {self.STATEIDENTIFIERS[state-1]: {atom.NR: atom.STATES[state] for atom in sorted(self.STATEATOMS, key=lambda x: x.NR)} for state in range(1, self.NPTB+1)} - - - def read_content_from_str(self, content:List[str]): + def states(self) -> dict: + return { + self.STATEIDENTIFIERS[state - 1]: { + atom.NR: atom.STATES[state] for atom in sorted(self.STATEATOMS, key=lambda x: x.NR) + } + for state in range(1, self.NPTB + 1) + } + + def read_content_from_str(self, content: List[str]): field = 0 NPD = None STATEIDENTIFIERS = None @@ -1422,33 +1706,32 @@ def read_content_from_str(self, content:List[str]): STATEATOMS = [] first = True stdid = False - i=1 + i = 1 for line in content: - if ("#" in line): + if "#" in line: comment = line - if("state_identifiers" in line): - stdid=True - elif(stdid): + if "state_identifiers" in line: + stdid = True + elif stdid: STATEIDENTIFIERS = line.replace("#", "").split() - stdid=False + stdid = False continue else: - if (field > 0): - if(first): - STATEATOMHEADER = ["atomI", "atomJ", "atomK", "atomL", "type1", "type2"] + if field > 0: + if first: + STATEATOMHEADER = ["atomI", "atomJ", "atomK", "atomL", "type1", "type2"] first = False state_line = {key: value for key, value in zip(STATEATOMHEADER, line.split())} - state_line.update({"NR":len(STATEATOMS)+1}) + state_line.update({"NR": len(STATEATOMS) + 1}) final_state_line = {key: state_line[key] for key in state_line if (not "type" in key)} - states = {1: state_line["type1"], - 2: state_line["type2"]} + states = {1: state_line["type1"], 2: state_line["type2"]} - final_state_line.update({"STATES":states}) + final_state_line.update({"STATES": states}) STATEATOMS.append(atom_lam_pertubation_state_dihedral(**final_state_line)) - elif (field == 0): + elif field == 0: NPD = int(line.strip()) field += 1 @@ -1460,64 +1743,87 @@ def read_content_from_str(self, content:List[str]): """ STR FUNCTIONS """ + def _state_STATEATOMHEADER_str(self): - state_format_pattern = "{:>5} {:>5} {:>5} {:>5}"+"".join([" {:>5} "for x in range(self.NPTB)])+"" + state_format_pattern = "{:>5} {:>5} {:>5} {:>5}" + "".join([" {:>5} " for x in range(self.NPTB)]) + "" return state_format_pattern.format(*self.STATEATOMHEADER) def block_to_string(self) -> str: result = self.name + self.line_seperator - result += "# NPD " + self.field_seperator + "NPTB = " + self.field_seperator + str(self.NPTB) + self.field_seperator+ self.line_seperator - result += self.field_seperator + str(self.NPD)+self.line_seperator + result += ( + "# NPD " + + self.field_seperator + + "NPTB = " + + self.field_seperator + + str(self.NPTB) + + self.field_seperator + + self.line_seperator + ) + result += self.field_seperator + str(self.NPD) + self.line_seperator result += "# " + self._state_STATEATOMHEADER_str() + self.line_seperator result += "".join(map(str, sorted(self.STATEATOMS, key=lambda x: x.NR))) - result += "END"+self.line_seperator + result += "END" + self.line_seperator return result class PERTIMROPERDIHH(_generic_gromos_block): - def __init__(self, STATEATOMS:List[atom_lam_pertubation_state_dihedral]=None, - STATEATOMHEADER: Tuple[str]= None, - NPD: int=None, - dummy_IMP = 22, content:List[str]=None): + def __init__( + self, + STATEATOMS: List[atom_lam_pertubation_state_dihedral] = None, + STATEATOMHEADER: Tuple[str] = None, + NPD: int = None, + dummy_IMP=22, + content: List[str] = None, + ): self.NPTB = 2 self.dummy_DIH = dummy_IMP - if(content is None): - if(STATEATOMHEADER is None): + if content is None: + if STATEATOMHEADER is None: self.STATEATOMHEADER = ["atomI", "atomJ", "atomK", "atomL", "type1", "type2"] else: self.STATEATOMHEADER = STATEATOMHEADER - - if(STATEATOMS is None): + if STATEATOMS is None: self.STATEATOMS = [] else: self.STATEATOMS = [] self.NPD = 0 - #self.add_state_atoms(STATEATOMS) + # self.add_state_atoms(STATEATOMS) super().__init__(used=True, name=__class__.__name__) else: super().__init__(used=True, name=__class__.__name__, content=content) # You can check yourself :) - if(not NPD is None and not len(STATEATOMS)==NPD): - raise ValueError("NPD must be equal to the length of STATEATOMS! NPD="+str(NPD)+"\t stateatoms"+str(len(STATEATOMS))+"\n\n"+str(self)) + if not NPD is None and not len(STATEATOMS) == NPD: + raise ValueError( + "NPD must be equal to the length of STATEATOMS! NPD=" + + str(NPD) + + "\t stateatoms" + + str(len(STATEATOMS)) + + "\n\n" + + str(self) + ) @property - def nStates(self)->int: + def nStates(self) -> int: return self.NPTB @property - def nTotalStateAtoms(self)->int: + def nTotalStateAtoms(self) -> int: return self.NPD @property - def states(self)->dict: - return {self.STATEIDENTIFIERS[state-1]: {atom.NR: atom.STATES[state] for atom in sorted(self.STATEATOMS, key=lambda x: x.NR)} for state in range(1, self.NPTB+1)} - - - def read_content_from_str(self, content:List[str]): + def states(self) -> dict: + return { + self.STATEIDENTIFIERS[state - 1]: { + atom.NR: atom.STATES[state] for atom in sorted(self.STATEATOMS, key=lambda x: x.NR) + } + for state in range(1, self.NPTB + 1) + } + + def read_content_from_str(self, content: List[str]): field = 0 NPD = None STATEIDENTIFIERS = None @@ -1525,33 +1831,32 @@ def read_content_from_str(self, content:List[str]): STATEATOMS = [] first = True stdid = False - i=1 + i = 1 for line in content: - if ("#" in line): + if "#" in line: comment = line - if("state_identifiers" in line): - stdid=True - elif(stdid): + if "state_identifiers" in line: + stdid = True + elif stdid: STATEIDENTIFIERS = line.replace("#", "").split() - stdid=False + stdid = False continue else: - if (field > 0): - if(first): - STATEATOMHEADER = ["atomI", "atomJ", "atomK", "atomL", "type1", "type2"] + if field > 0: + if first: + STATEATOMHEADER = ["atomI", "atomJ", "atomK", "atomL", "type1", "type2"] first = False state_line = {key: value for key, value in zip(STATEATOMHEADER, line.split())} - state_line.update({"NR":len(STATEATOMS)+1}) + state_line.update({"NR": len(STATEATOMS) + 1}) final_state_line = {key: state_line[key] for key in state_line if (not "type" in key)} - states = {1: state_line["type1"], - 2: state_line["type2"]} + states = {1: state_line["type1"], 2: state_line["type2"]} - final_state_line.update({"STATES":states}) + final_state_line.update({"STATES": states}) STATEATOMS.append(atom_lam_pertubation_state_dihedral(**final_state_line)) - elif (field == 0): + elif field == 0: NPD = int(line.strip()) field += 1 @@ -1563,16 +1868,24 @@ def read_content_from_str(self, content:List[str]): """ STR FUNCTIONS """ + def _state_STATEATOMHEADER_str(self): - state_format_pattern = "{:>5} {:>5} {:>5} {:>5}"+"".join([" {:>5} "for x in range(self.NPTB)])+"" + state_format_pattern = "{:>5} {:>5} {:>5} {:>5}" + "".join([" {:>5} " for x in range(self.NPTB)]) + "" return state_format_pattern.format(*self.STATEATOMHEADER) def block_to_string(self) -> str: result = self.name + self.line_seperator - result += "# NPD " + self.field_seperator + "NPTB = " + self.field_seperator + str(self.NPTB) + self.field_seperator+ self.line_seperator - result += self.field_seperator + str(self.NPD)+self.line_seperator + result += ( + "# NPD " + + self.field_seperator + + "NPTB = " + + self.field_seperator + + str(self.NPTB) + + self.field_seperator + + self.line_seperator + ) + result += self.field_seperator + str(self.NPD) + self.line_seperator result += "# " + self._state_STATEATOMHEADER_str() + self.line_seperator result += "".join(map(str, sorted(self.STATEATOMS, key=lambda x: x.NR))) - result += "END"+self.line_seperator + result += "END" + self.line_seperator return result - diff --git a/pygromos/files/blocks/qmmm_blocks.py b/pygromos/files/blocks/qmmm_blocks.py index cc3dc6a8..d8a7822d 100644 --- a/pygromos/files/blocks/qmmm_blocks.py +++ b/pygromos/files/blocks/qmmm_blocks.py @@ -34,12 +34,18 @@ def to_string(self): # the first 24 characters or so are ignored by Gromos # use spaces instead of tabs and format the resulting # table nicely using ljust and rjust - str_line = str(self.QMEN).ljust(27) + str(self.QMEI).rjust(6) + str(self.QMEZ).rjust(6) + str(self.QMEB).rjust(6) + "\n" + str_line = ( + str(self.QMEN).ljust(27) + + str(self.QMEI).rjust(6) + + str(self.QMEZ).rjust(6) + + str(self.QMEB).rjust(6) + + "\n" + ) return str_line class QMZONE(_topology_table_block): - NBON:int = 1 + NBON: int = 1 table_header: Iterable[str] = ["QMEN", "QMEI", "QMEZ", "QMEB"] table_line_type = qmzone_field @@ -47,7 +53,7 @@ def __init__(self, content: Union[Iterable[qmzone_field], str]): super().__init__(content=content, FORCEFIELD=None, MAKETOPVERSION=None) def block_to_string(self) -> str: - result = self.name + "\n" # QMZONE + result = self.name + "\n" # QMZONE result += f"{self.comment_char} {self.table_header[0]}".ljust(27) for element in self.table_header[1:]: result += element.rjust(6) @@ -57,6 +63,7 @@ def block_to_string(self) -> str: result += "END\n" return result + class QMUNIT(_topology_block): table_header: Iterable[str] = ["QLGL", "QEGE", "QCGC", "QIGI"] @@ -67,15 +74,23 @@ class QMUNIT(_topology_block): Parameters ---------- QLGL : float - QM length to Gromos length (e.g. Bohr to nm) + QM length to Gromos length (e.g. Bohr to nm) QEGE : float QM energy to Gromos energy (e.g. Hartree to kJ / mol) QCGC : float - Gromos charge to QM charge + Gromos charge to QM charge QIGI : float QM input units to Gromos input units (e.g. Angstrom to nm) """ - def __init__(self, content:(str or dict or None or __class__), QLGL:float=0.052918, QEGE:float=2625.50, QCGC:float=1.0, QIGI:float=0.1): + + def __init__( + self, + content: (str or dict or None or __class__), + QLGL: float = 0.052918, + QEGE: float = 2625.50, + QCGC: float = 1.0, + QIGI: float = 0.1, + ): super().__init__(FORCEFIELD=None, MAKETOPVERSION=None, content=content) if content is None: self.QLGL = float(QLGL) @@ -93,38 +108,54 @@ def read_content_from_str(self, content: str): except IOError as e: print("Error while reading QMUNIT block: " + str(e)) - def block_to_string(self) -> str: - result = self.name + "\n" # QMUNIT + def block_to_string(self) -> str: + result = self.name + "\n" # QMUNIT result += f"{self.comment_char} {self.table_header[0]}".ljust(17) for element in self.table_header[1:]: result += element.ljust(15) result += "\n" - result += str(self.QLGL) + self.field_seperator + str(self.QEGE) + self.field_seperator + str(self.QCGC) + self.field_seperator + str(self.QIGI) + self.line_seperator + result += ( + str(self.QLGL) + + self.field_seperator + + str(self.QEGE) + + self.field_seperator + + str(self.QCGC) + + self.field_seperator + + str(self.QIGI) + + self.line_seperator + ) result += "END\n" return result + # There should be only of these blocks in the .qmmm file + class MNDOELEMENTS(_topology_block): - def __init__(self, content:(str or dict or None or __class__)): + def __init__(self, content: (str or dict or None or __class__)): super().__init__(FORCEFIELD=None, MAKETOPVERSION=None, content=content) + class TURBOMOLEELEMENTS(_topology_block): - def __init__(self, content:(str or dict or None or __class__)): + def __init__(self, content: (str or dict or None or __class__)): super().__init__(FORCEFIELD=None, MAKETOPVERSION=None, content=content) + class DFTBELEMENTS(_topology_block): - def __init__(self, content:(str or dict or None or __class__)): + def __init__(self, content: (str or dict or None or __class__)): super().__init__(FORCEFIELD=None, MAKETOPVERSION=None, content=content) + class MOPACELEMENTS(_topology_block): - def __init__(self, content:(str or dict or None or __class__)): + def __init__(self, content: (str or dict or None or __class__)): super().__init__(FORCEFIELD=None, MAKETOPVERSION=None, content=content) + class ORCAELEMENTS(_topology_block): - def __init__(self, content:(str or dict or None or __class__)): + def __init__(self, content: (str or dict or None or __class__)): super().__init__(FORCEFIELD=None, MAKETOPVERSION=None, content=content) + class XTBELEMENTS(_topology_block): - def __init__(self, content:(str or dict or None or __class__)): - super().__init__(FORCEFIELD=None, MAKETOPVERSION=None, content=content) \ No newline at end of file + def __init__(self, content: (str or dict or None or __class__)): + super().__init__(FORCEFIELD=None, MAKETOPVERSION=None, content=content) diff --git a/pygromos/files/blocks/replica_exchange_blocks.py b/pygromos/files/blocks/replica_exchange_blocks.py index 2194d4fd..50f0edb5 100644 --- a/pygromos/files/blocks/replica_exchange_blocks.py +++ b/pygromos/files/blocks/replica_exchange_blocks.py @@ -1,6 +1,7 @@ from pygromos.files.blocks._general_blocks import _generic_gromos_block, _generic_field from typing import Dict + class repex_system(_generic_gromos_block): def __init__(self, s: list, T: (float or list), state_eir: dict): super().__init__(used=True, name="REPLICAEXSYSTEM") @@ -22,7 +23,9 @@ def block_to_string(self) -> str: result += "s (RE-EDS) \t " + " ".join(map(str, self.s)) + "\n" for state in self.state_eir.keys(): - result += "eir(s), numstate = " + str(state) + " (RE - EDS) " + "\t".join(map(str, self.state_eir[state])) + "\n" + result += ( + "eir(s), numstate = " + str(state) + " (RE - EDS) " + "\t".join(map(str, self.state_eir[state])) + "\n" + ) # result ="END\n" return result @@ -30,26 +33,42 @@ def block_to_string(self) -> str: class replica_stat(_generic_field): ID: int - partner:int - run:int + partner: int + run: int - li:float - Ti:float - Epoti:float + li: float + Ti: float + Epoti: float - lj:float - Tj:float - Epotj:float + lj: float + Tj: float + Epotj: float - p:float + p: float s: bool - si:float - sj:float + si: float + sj: float state_potentials: Dict[str, float] - def __init__(self, ID: int, partner: int, run: int, Ti: float, Epoti: float, Tj: float, Epotj: float, - p: float, s: bool, si: float, sj: float, state_potentials: dict=None, potentials: dict=None, li: float = None, lj: float = None): + def __init__( + self, + ID: int, + partner: int, + run: int, + Ti: float, + Epoti: float, + Tj: float, + Epotj: float, + p: float, + s: bool, + si: float, + sj: float, + state_potentials: dict = None, + potentials: dict = None, + li: float = None, + lj: float = None, + ): """ Parameters @@ -70,9 +89,9 @@ def __init__(self, ID: int, partner: int, run: int, Ti: float, Epoti: float, Tj: li : lj : """ - if(isinstance(state_potentials, type(None)) and isinstance(potentials, type(None))): + if isinstance(state_potentials, type(None)) and isinstance(potentials, type(None)): raise Exception("Need either state_potential or potentials for replica_statistic.") - elif(isinstance(state_potentials, type(None)) and not isinstance(potentials, type(None))): + elif isinstance(state_potentials, type(None)) and not isinstance(potentials, type(None)): state_potentials = potentials self.ID = int(ID) @@ -94,6 +113,24 @@ def __init__(self, ID: int, partner: int, run: int, Ti: float, Epoti: float, Tj: self.state_potentials = dict(state_potentials) def to_string(self) -> str: - return "\t".join( - [str(self.ID), str(self.partner), str(self.run), str(self.li), str(self.Ti), str(self.Epoti), str(self.lj), str(self.Tj), str(self.Epotj), - str(self.p), str(self.s), str(self.si), str(self.sj), " ".join(list(map(str, self.state_potentials.values())))]) + "\n" \ No newline at end of file + return ( + "\t".join( + [ + str(self.ID), + str(self.partner), + str(self.run), + str(self.li), + str(self.Ti), + str(self.Epoti), + str(self.lj), + str(self.Tj), + str(self.Epotj), + str(self.p), + str(self.s), + str(self.si), + str(self.sj), + " ".join(list(map(str, self.state_potentials.values()))), + ] + ) + + "\n" + ) diff --git a/pygromos/files/blocks/topology_blocks.py b/pygromos/files/blocks/topology_blocks.py index cb176bc6..c2b158ef 100644 --- a/pygromos/files/blocks/topology_blocks.py +++ b/pygromos/files/blocks/topology_blocks.py @@ -38,10 +38,26 @@ class geometric_code(Enum): """ FIELDS """ + + class atom_pair_distanceRes(_generic_field): - def __init__(self, i1: int, j1: int, k1: int, l1: int, type1: (geometric_code or int), - i2: int, j2: int, k2: int, l2: int, type2: (geometric_code or int), - r0: float, w0: float, rah: (distant_Restraint_Type or int), comment: str = ""): + def __init__( + self, + i1: int, + j1: int, + k1: int, + l1: int, + type1: (geometric_code or int), + i2: int, + j2: int, + k2: int, + l2: int, + type2: (geometric_code or int), + r0: float, + w0: float, + rah: (distant_Restraint_Type or int), + comment: str = "", + ): """ Parameters @@ -83,9 +99,9 @@ def __init__(self, i1: int, j1: int, k1: int, l1: int, type1: (geometric_code or self.atom1k = int(k1) self.atom1l = int(l1) - if (type(type1) is geometric_code): + if type(type1) is geometric_code: self.atom1ic = type1 - elif (type(type1) is int or (type(type1) is str and str(type1).isdigit())): + elif type(type1) is int or (type(type1) is str and str(type1).isdigit()): self.atom1ic = geometric_code(int(type1)) else: raise ValueError("geometric index.rst atom1ic in atom_pair_distanceRes unknown\n" + str(type1)) @@ -95,18 +111,18 @@ def __init__(self, i1: int, j1: int, k1: int, l1: int, type1: (geometric_code or self.atom2k = int(k2) self.atom2l = int(l2) - if (type(type2) is geometric_code): + if type(type2) is geometric_code: self.atom2ic = type2 - elif (type(type2) is int or (type(type2) is str and str(type2).isdigit())): + elif type(type2) is int or (type(type2) is str and str(type2).isdigit()): self.atom2ic = geometric_code(int(type2)) else: raise ValueError("geometric index.rst atom2ic in atom_pair_distanceRes unknown\n" + str(type2)) self.radius_0 = float(r0) self.weight = float(w0) - if (type(rah) is int or (type(rah) is str and str(rah).isdigit())): + if type(rah) is int or (type(rah) is str and str(rah).isdigit()): self.disResType = distant_Restraint_Type(int(rah)) - elif (type(rah) is distant_Restraint_Type): + elif type(rah) is distant_Restraint_Type: self.disResType = rah else: raise ValueError("DisresType in atom_pair_distanceRes unknown\n" + str(rah)) @@ -115,15 +131,29 @@ def __init__(self, i1: int, j1: int, k1: int, l1: int, type1: (geometric_code or raise IOError("COULD NOT convert a parameter for distancerestraint field into correct form!") def to_string(self): - if (len(self.comment) > 0 and not self.comment.endswith("\n")): + if len(self.comment) > 0 and not self.comment.endswith("\n"): self.comment += "\n" - return self.comment + "{:>5} {:>5} {:>5} {:>5} {:>5} {:>5} {:>5} {:>5} {:>5} {:>5} {:10.5f} {:10.5f} {:>3}\n".format( - self.atom1i, self.atom1j, self.atom1k, self.atom1l, self.atom1ic.value, self.atom2i, self.atom2j, - self.atom2k, - self.atom2l, self.atom2ic.value, self.radius_0, self.weight, self.disResType.value) + return ( + self.comment + + "{:>5} {:>5} {:>5} {:>5} {:>5} {:>5} {:>5} {:>5} {:>5} {:>5} {:10.5f} {:10.5f} {:>3}\n".format( + self.atom1i, + self.atom1j, + self.atom1k, + self.atom1l, + self.atom1ic.value, + self.atom2i, + self.atom2j, + self.atom2k, + self.atom2l, + self.atom2ic.value, + self.radius_0, + self.weight, + self.disResType.value, + ) + ) -class atom_mass_type(_generic_field): +class atom_mass_type(_generic_field): def __init__(self, N: int, ATMAS: float, ATMASN: str, comment: str = ""): self.N = N self.ATMAS = ATMAS @@ -140,8 +170,16 @@ def to_string(self): class bond_type(_generic_field): - def __init__(self, ICB: int, CB: float, HB: float, B0: float, atomI: Union[str, Iterable[str]], - atomJ: Union[str, Iterable[str]], specialNumber: int): + def __init__( + self, + ICB: int, + CB: float, + HB: float, + B0: float, + atomI: Union[str, Iterable[str]], + atomJ: Union[str, Iterable[str]], + specialNumber: int, + ): """ GROMOS bond-stretching parameters for one possible bond @@ -171,13 +209,15 @@ def __init__(self, ICB: int, CB: float, HB: float, B0: float, atomI: Union[str, self.specialNumber = specialNumber def to_string(self): - str_line = self.comment + "\t{:<3} {:<1.7f} {:<1.7f} {:<1.7f}\n".format(self.ICB, self.CB, self.HB, self.B0) + str_line = self.comment + "\t{:<3} {:<1.7f} {:<1.7f} {:<1.7f}\n".format( + self.ICB, self.CB, self.HB, self.B0 + ) atomI = self.atomI atomJ = self.atomJ - if(isinstance(atomI, list)): + if isinstance(atomI, list): atomI = ",".join(atomI) - if(isinstance(atomJ, list)): + if isinstance(atomJ, list): atomJ = ",".join(atomJ) str_line += "#\t{:<3} - {:<3} {:<5}\n".format(atomI, atomJ, self.specialNumber) @@ -185,8 +225,17 @@ def to_string(self): class angle_type(_generic_field): - def __init__(self, ICT: int, CT: float, CHT: float, T0: float, atomI: Union[str, Iterable[str]], - atomJ: Union[str, Iterable[str]], atomK: Union[str, Iterable[str]], specialNumber: int): + def __init__( + self, + ICT: int, + CT: float, + CHT: float, + T0: float, + atomI: Union[str, Iterable[str]], + atomJ: Union[str, Iterable[str]], + atomK: Union[str, Iterable[str]], + specialNumber: int, + ): """ GROMOS bond-stretching parameters for one possible bond @@ -219,16 +268,18 @@ def __init__(self, ICT: int, CT: float, CHT: float, T0: float, atomI: Union[str, self.specialNumber = specialNumber def to_string(self): - str_line = self.comment + "\t{:<3} {:<1.7f} {:<1.7f} {:<1.7f}\n".format(self.ICT, self.CT, self.CHT, self.T0) + str_line = self.comment + "\t{:<3} {:<1.7f} {:<1.7f} {:<1.7f}\n".format( + self.ICT, self.CT, self.CHT, self.T0 + ) atomI = self.atomI atomJ = self.atomJ atomK = self.atomK - if (isinstance(atomI, list)): + if isinstance(atomI, list): atomI = ",".join(atomI) - if (isinstance(atomJ, list)): + if isinstance(atomJ, list): atomJ = ",".join(atomJ) - if (isinstance(atomK, list)): + if isinstance(atomK, list): atomK = ",".join(atomK) str_line += "#\t{:<3} - {:<3} - {:<3} {:<5}\n".format(atomI, atomJ, atomK, self.specialNumber) @@ -236,8 +287,19 @@ def to_string(self): class dihedral_type(_generic_field): - def __init__(self, ICP: int, CP: float, PD: float, NP: int, atomI: str, atomJ: str, atomK: str, atomL: str, - special_number: float, concrete_example: str = ""): + def __init__( + self, + ICP: int, + CP: float, + PD: float, + NP: int, + atomI: str, + atomJ: str, + atomK: str, + atomL: str, + special_number: float, + concrete_example: str = "", + ): """ GROMOS improper (harmonic) dihedral angle parameters @@ -283,17 +345,19 @@ def to_string(self): atomK = self.atomK atomL = self.atomL - if (isinstance(atomI, list)): + if isinstance(atomI, list): atomI = ",".join(atomI) - if (isinstance(atomJ, list)): + if isinstance(atomJ, list): atomJ = ",".join(atomJ) - if (isinstance(atomK, list)): + if isinstance(atomK, list): atomK = ",".join(atomK) - if (isinstance(atomL, list)): + if isinstance(atomL, list): atomL = ",".join(atomL) - str_line += "#\t{:<3} - {:<3} - {:<3} - {:<3} {:<5}\n".format(atomI, atomJ, atomK, atomL, self.special_number) - str_line += "#\t{:20}\n".format(self.concrete_example.replace("#","")) + str_line += "#\t{:<3} - {:<3} - {:<3} - {:<3} {:<5}\n".format( + atomI, atomJ, atomK, atomL, self.special_number + ) + str_line += "#\t{:20}\n".format(self.concrete_example.replace("#", "")) return str_line @@ -329,9 +393,18 @@ def to_string(self): class single_atom_lj_pair_type(_generic_field): - - def __init__(self, IAC: int, TYPE: str, C6: float, C12_1: float, C12_2: float, C12_3: float, - CS6: float, CS12: float, LJ14PAIR: Iterable[float]): + def __init__( + self, + IAC: int, + TYPE: str, + C6: float, + C12_1: float, + C12_2: float, + C12_3: float, + CS6: float, + CS12: float, + LJ14PAIR: Iterable[float], + ): """ Parameters @@ -365,9 +438,9 @@ def __init__(self, IAC: int, TYPE: str, C6: float, C12_1: float, C12_2: float, C def to_string(self): str_line = self.comment + "#\tIAC TYPE C6 C12_1 C12_2 C12_3\n" - str_line += "\t{:<3} {:<3} {:<1.7f} {:<1.7f} {:<1.7f} {:<1.7f}\n".format(self.IAC, self.TYPE, - self.C6, self.C12_1, - self.C12_2, self.C12_3) + str_line += "\t{:<3} {:<3} {:<1.7f} {:<1.7f} {:<1.7f} {:<1.7f}\n".format( + self.IAC, self.TYPE, self.C6, self.C12_1, self.C12_2, self.C12_3 + ) str_line += "#\t CS6 CS12\n" str_line += "\t{:<3f} {:<3f}\n".format(self.CS6, self.CS12) str_line += "#\tLJPAIRS\n" @@ -387,10 +460,9 @@ def __init__(self, IACI: int, IACJ: int, C6: float, C12_1: float, C12_2: float, self.C12_3 = C12_3 def to_string(self): - str_line = self.comment + "\t{:<3} {:<3} {:<1.7f} {:<1.7f} {:<1.7f} {:<1.7f}\n".format(self.IACI, self.IACI, - self.C6, self.C12_1, - self.C12_2, - self.C12_3) + str_line = self.comment + "\t{:<3} {:<3} {:<1.7f} {:<1.7f} {:<1.7f} {:<1.7f}\n".format( + self.IACI, self.IACI, self.C6, self.C12_1, self.C12_2, self.C12_3 + ) return str_line @@ -420,7 +492,9 @@ def __init__(self, c): self.c def to_string(self): - str_line = self.comment + "\t{:<3}\n".format(self.c, ) + str_line = self.comment + "\t{:<3}\n".format( + self.c, + ) return str_line @@ -437,10 +511,11 @@ def to_string(self): # general Topo Blocks + class FORCEFIELD(_generic_gromos_block): NAME: str - def __init__(self, NAME: str=None, content=None): + def __init__(self, NAME: str = None, content=None): if content is None: super().__init__(name=self.__class__.__name__, used=True) self.NAME = NAME[0].strip() @@ -450,15 +525,16 @@ def __init__(self, NAME: str=None, content=None): def block_to_string(self) -> str: result = self.name + self.line_seperator - #result += self.NAME + self.line_seperator + # result += self.NAME + self.line_seperator result += "END" + self.line_seperator return result + class MAKETOPVERSION(_generic_gromos_block): VERSION: str - def __init__(self, VERSION: str=None, content=None): - if(content is None): + def __init__(self, VERSION: str = None, content=None): + if content is None: super().__init__(name=self.__class__.__name__, used=True) self.VERSION = VERSION[0].strip() else: @@ -471,6 +547,7 @@ def block_to_string(self) -> str: result += "END" + self.line_seperator return result + class _topology_block(_generic_gromos_block): FORCEFIELD: FORCEFIELD MAKETOPVERSION: MAKETOPVERSION @@ -485,15 +562,14 @@ class _iterable_topology_block(_iterable_gromos_block): FORCEFIELD: FORCEFIELD MAKETOPVERSION: MAKETOPVERSION - def __init__(self, FORCEFIELD:FORCEFIELD=None, MAKETOPVERSION:MAKETOPVERSION=None, content = None): - super().__init__(self.__class__.__name__, used=True, content = content) + def __init__(self, FORCEFIELD: FORCEFIELD = None, MAKETOPVERSION: MAKETOPVERSION = None, content=None): + super().__init__(self.__class__.__name__, used=True, content=content) self.FORCEFIELD = FORCEFIELD self.MAKETOPVERSION = MAKETOPVERSION - def __deepcopy__(self, memo): - #return block as string, split by line and cut block title and END - newContent= self.block_to_string().split(self.line_seperator)[1:-2] + # return block as string, split by line and cut block title and END + newContent = self.block_to_string().split(self.line_seperator)[1:-2] block = type(self)(content=newContent) return block @@ -504,9 +580,17 @@ def __deepcopy__(self, memo): """ Restraints Blocks """ + + class DISTANCERESSPEC(_generic_gromos_block): - def __init__(self, KDISH: int=None, KDISC: int=None, RESTRAINTHEADER: list=None, RESTRAINTS: list=None, - content:List[str]=None): + def __init__( + self, + KDISH: int = None, + KDISC: int = None, + RESTRAINTHEADER: list = None, + RESTRAINTS: list = None, + content: List[str] = None, + ): """ Parameters @@ -517,14 +601,15 @@ def __init__(self, KDISH: int=None, KDISC: int=None, RESTRAINTHEADER: list=None, RESTRAINTS : """ - if(content is None): - content = ["# KDISH, KDISC\n", str(KDISH)+"\t"+str(KDISC), - "\t".join(RESTRAINTHEADER), - ]+list(map(str, RESTRAINTS)) + if content is None: + content = [ + "# KDISH, KDISC\n", + str(KDISH) + "\t" + str(KDISC), + "\t".join(RESTRAINTHEADER), + ] + list(map(str, RESTRAINTS)) super().__init__(used=True, name="DISTANCERESSPEC", content=content) - - def read_content_from_str(self, content:List[str]): + def read_content_from_str(self, content: List[str]): # readout KDISH or KDISC keys = content[0].replace("#", "").strip().split() KDISH, KDISC = content[1].split() @@ -535,7 +620,7 @@ def read_content_from_str(self, content:List[str]): key_dict = {"i": 1, "j": 1, "k": 1, "l": 1, "type": 1} renamed_header = [] for x in line_header: - if (x in key_dict): + if x in key_dict: renamed_header.append(x + str(key_dict[x])) key_dict[x] += 1 else: @@ -545,11 +630,11 @@ def read_content_from_str(self, content:List[str]): # read restraints RESTRAINTS = [] for line in content[3:]: - if (not line.startswith("#") and len(line.split()) == len(RESTRAINTHEADER)): + if not line.startswith("#") and len(line.split()) == len(RESTRAINTHEADER): values = line.split() - RESTRAINTS_dict= {key: values[RESTRAINTHEADER.index(key)] for key in RESTRAINTHEADER} + RESTRAINTS_dict = {key: values[RESTRAINTHEADER.index(key)] for key in RESTRAINTHEADER} RESTRAINTS.append(atom_pair_distanceRes(**RESTRAINTS_dict)) - elif (line.startswith("#")): + elif line.startswith("#"): continue else: print("WARNING! could not Read in :" + line) @@ -560,14 +645,13 @@ def read_content_from_str(self, content:List[str]): self.RESTRAINTHEADER = RESTRAINTHEADER self.RESTRAINTS = RESTRAINTS - - def block_to_string(self) -> str: result = self.name + self.line_seperator result += "# KDISH" + self.field_seperator + "KDISC" + self.line_seperator result += self.field_seperator + str(self.KDISH) + self.field_seperator + str(self.KDISC) + self.line_seperator result += "#{:>4} {:>5} {:>5} {:>5} {:>5} {:>5} {:>5} {:>5} {:>5} {:>5} {:>10} {:>10} {:>3}\n".format( - *self.RESTRAINTHEADER) + *self.RESTRAINTHEADER + ) for x in self.RESTRAINTS: result += x.to_string() result += "END\n" @@ -587,33 +671,39 @@ class MASSATOMTYPECODE(_iterable_topology_block): NRMATY: int NMATY: int table_header: Iterable[str] = ["N", "ATMAS", "ATMASN"] - def __init__(self, content: Union[Iterable[atom_mass_type], Iterable[str]], - FORCEFIELD: FORCEFIELD = None, MAKETOPVERSION: MAKETOPVERSION = None, - NRMATY: int = None, NMATY: int = None): - super().__init__(FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, content = content) + + def __init__( + self, + content: Union[Iterable[atom_mass_type], Iterable[str]], + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + NRMATY: int = None, + NMATY: int = None, + ): + super().__init__(FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, content=content) self._content = [] - if (isinstance(content, list) and all([isinstance(x, str) for x in content])): + if isinstance(content, list) and all([isinstance(x, str) for x in content]): self.read_content_from_str(content) - elif (isinstance(content, Iterable) and all([isinstance(x, atom_mass_type) for x in content])): + elif isinstance(content, Iterable) and all([isinstance(x, atom_mass_type) for x in content]): self.content = content else: raise IOError("I don't understand the type of content: " + str(type(content))) - if (NRMATY is None): + if NRMATY is None: self.NRMATY = len(self.content) - elif (isinstance(NRMATY, int)): - if (NRMATY == len(self.content)): # CHECK FOR POSSIBLE ERROR + elif isinstance(NRMATY, int): + if NRMATY == len(self.content): # CHECK FOR POSSIBLE ERROR self.NRMATY = NRMATY else: raise ValueError("IN MASSATOMTYPECODE NRMATY is not equal to the ammount of MASSATOMTYPES.") else: raise IOError("I don't understand the type of NRMATY: " + str(type(NRMATY))) - if (NMATY is None): + if NMATY is None: self.NMATY = max([x.N for x in self.content]) - elif (isinstance(NMATY, int)): - if (NMATY == max([x.N for x in self.content])): # CHECK FOR POSSIBLE ERROR + elif isinstance(NMATY, int): + if NMATY == max([x.N for x in self.content]): # CHECK FOR POSSIBLE ERROR self.NMATY = NMATY else: raise ValueError("IN MASSATOMTYPECODE NMATY is not the maximal Mass atom type code.") @@ -622,18 +712,18 @@ def __init__(self, content: Union[Iterable[atom_mass_type], Iterable[str]], def read_content_from_str(self, content: (str, list)): - if (isinstance(content, str)): + if isinstance(content, str): lines = content.split("\n") else: lines = content - if ("NRMATY" in lines[0] and "NMATY" in lines[0]): + if "NRMATY" in lines[0] and "NMATY" in lines[0]: NRMATY, NMATY = list(map(int, lines[1].strip().split())) table_start = 0 for line in lines: table_start += 1 - if (all([field in line for field in self.table_header])): + if all([field in line for field in self.table_header]): break if table_start == len(lines): @@ -643,14 +733,14 @@ def read_content_from_str(self, content: (str, list)): mass_atom_type_code, mass, mass_atom_name = field.strip().split() self.content.append(atom_mass_type(int(mass_atom_type_code), float(mass), str(mass_atom_name))) - #print(self.content) + # print(self.content) def block_to_string(self) -> str: result = self.name + "\n" - result += "#"+self.field_seperator+"NRMATY"+self.field_seperator+"NMATY"+self.line_seperator + result += "#" + self.field_seperator + "NRMATY" + self.field_seperator + "NMATY" + self.line_seperator result += self.field_seperator + str(self.NRMATY) + self.field_seperator + str(self.NMATY) + self.line_seperator - result += "# TABLE CONTENT: "+self.line_seperator - result += "#"+self.field_seperator+self.field_seperator.join(self.table_header)+self.line_seperator + result += "# TABLE CONTENT: " + self.line_seperator + result += "#" + self.field_seperator + self.field_seperator.join(self.table_header) + self.line_seperator for x in self.content: result += x.to_string() result += "END\n" @@ -663,10 +753,14 @@ class BONDSTRETCHTYPECODE(_iterable_topology_block): NBTY: int table_header: Iterable[str] = ["ICB(H)[N]", "CB[N]", "HB[N]", "B0[N]"] - def __init__(self, content: Union[Iterable[bond_type], str], - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None, - NRBTY: int = None, NBTY: int = None): + def __init__( + self, + content: Union[Iterable[bond_type], str], + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + NRBTY: int = None, + NBTY: int = None, + ): """ GROMOS bond-stretching parameters @@ -680,29 +774,29 @@ def __init__(self, content: Union[Iterable[bond_type], str], NBTY : int, optional Number of maximal bond index.rst """ - super().__init__(FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, content = content) + super().__init__(FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, content=content) - if (isinstance(content, list) and all([isinstance(x, str) for x in content])): + if isinstance(content, list) and all([isinstance(x, str) for x in content]): self.read_content_from_str(content) - elif (isinstance(content, Iterable) and all([isinstance(x, atom_mass_type) for x in content])): + elif isinstance(content, Iterable) and all([isinstance(x, atom_mass_type) for x in content]): self.content = content else: raise IOError("I don't understand the type of content: " + str(type(content))) - if (NRBTY is None): + if NRBTY is None: self.NRBTY = len(self.content) - elif (isinstance(NRBTY, int)): - if (NRBTY == len(self.content)): # CHECK FOR POSSIBLE ERROR + elif isinstance(NRBTY, int): + if NRBTY == len(self.content): # CHECK FOR POSSIBLE ERROR self.NRBTY = NRBTY else: raise ValueError("IN MASSATOMTYPECODE NRMATY is not equal to the ammount of MASSATOMTYPES.") else: raise IOError("I don't understand the type of NRMATY: " + str(type(NRBTY))) - if (NBTY is None): + if NBTY is None: self.NBTY = max([x.ICB for x in self.content]) - elif (isinstance(NBTY, int)): - if (NBTY == max([x.ICB for x in self.content])): # CHECK FOR POSSIBLE ERROR + elif isinstance(NBTY, int): + if NBTY == max([x.ICB for x in self.content]): # CHECK FOR POSSIBLE ERROR self.NBTY = NBTY else: raise ValueError("IN MASSATOMTYPECODE NMATY is not the maximal Mass atom type code.") @@ -710,7 +804,7 @@ def __init__(self, content: Union[Iterable[bond_type], str], raise IOError("I don't understand the type of NMATY: " + str(type(NBTY))) def read_content_from_str(self, content: str): - if (isinstance(content, str)): + if isinstance(content, str): lines = content.split("\n") else: lines = content @@ -718,7 +812,7 @@ def read_content_from_str(self, content: str): table_start = 0 for line in lines: table_start += 1 - if (all([field in line for field in self.table_header])): + if all([field in line for field in self.table_header]): break if table_start == len(lines): @@ -726,32 +820,39 @@ def read_content_from_str(self, content: str): table_lines = lines[table_start:] for field in table_lines: - if (not field.strip().startswith("#") and not len(field.strip()) == 0): + if not field.strip().startswith("#") and not len(field.strip()) == 0: ICB, CB, HB, B0 = field.strip().split() # nasty next line formatting of gromos comment_index = table_lines.index(field) + 1 - clean = re.sub('\(.*?\)', '', table_lines[comment_index]) + clean = re.sub("\(.*?\)", "", table_lines[comment_index]) split_line = [x for x in clean.replace("#", "").replace("-", "").strip().split(" ") if (len(x) > 0)] split_line = [x.split(",") if ("," in x) else x for x in split_line] - if (len(split_line) == 3): + if len(split_line) == 3: atomI, atomJ, specialNumber = split_line - elif (len(split_line) == 2): + elif len(split_line) == 2: atomI, atomJ = split_line specialNumber = 0 # generate line - params = bond_type(ICB=int(ICB), CB=float(CB), HB=float(HB), B0=float(B0), - atomI=atomI, atomJ=atomJ, specialNumber=float(specialNumber)) + params = bond_type( + ICB=int(ICB), + CB=float(CB), + HB=float(HB), + B0=float(B0), + atomI=atomI, + atomJ=atomJ, + specialNumber=float(specialNumber), + ) self.content.append(params) def block_to_string(self) -> str: result = self.name + "\n" - result += "#"+self.field_seperator+"NRBTY"+self.field_seperator+"NBTY"+self.line_seperator - result += "# TABLE CONTENT: "+self.line_seperator - result += self.field_seperator+str(self.NRBTY)+self.field_seperator+str(self.NBTY)+self.line_seperator - result += "#"+self.field_seperator+self.field_seperator.join(self.table_header)+self.line_seperator + result += "#" + self.field_seperator + "NRBTY" + self.field_seperator + "NBTY" + self.line_seperator + result += "# TABLE CONTENT: " + self.line_seperator + result += self.field_seperator + str(self.NRBTY) + self.field_seperator + str(self.NBTY) + self.line_seperator + result += "#" + self.field_seperator + self.field_seperator.join(self.table_header) + self.line_seperator for x in self.content: result += x.to_string() result += "END\n" @@ -763,11 +864,14 @@ class BONDANGLEBENDTYPECODE(_iterable_topology_block): NTTY: int table_header: Iterable[str] = ["ICT(H)[N]", "CT[N]", "CHT[N]", "(T0[N])"] - - def __init__(self, content: Union[Iterable[angle_type], str], - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None, - NRTTY: int = None, NTTY: int = None): + def __init__( + self, + content: Union[Iterable[angle_type], str], + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + NRTTY: int = None, + NTTY: int = None, + ): """ GROMOS bond-stretching parameters @@ -781,29 +885,29 @@ def __init__(self, content: Union[Iterable[angle_type], str], NBTY : int, optional Number of maximal bond index.rst """ - super().__init__(FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, content = content) + super().__init__(FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, content=content) - if (isinstance(content, list) and all([isinstance(x, str) for x in content])): + if isinstance(content, list) and all([isinstance(x, str) for x in content]): self.read_content_from_str(content) - elif (isinstance(content, Iterable) and all([isinstance(x, atom_mass_type) for x in content])): + elif isinstance(content, Iterable) and all([isinstance(x, atom_mass_type) for x in content]): self.content = content else: raise IOError("I don't understand the type of content: " + str(type(content))) - if (NRTTY is None): + if NRTTY is None: self.NRTTY = len(self.content) - elif (isinstance(NRTTY, int)): - if (NRTTY == len(self.content)): # CHECK FOR POSSIBLE ERROR + elif isinstance(NRTTY, int): + if NRTTY == len(self.content): # CHECK FOR POSSIBLE ERROR self.NRBTY = NRTTY else: raise ValueError("IN MASSATOMTYPECODE NRMATY is not equal to the ammount of MASSATOMTYPES.") else: raise IOError("I don't understand the type of NRMATY: " + str(type(NRTTY))) - if (NTTY is None): + if NTTY is None: self.NTTY = max([x.ICT for x in self.content]) - elif (isinstance(NTTY, int)): - if (NTTY == max([x.ICT for x in self.content])): # CHECK FOR POSSIBLE ERROR + elif isinstance(NTTY, int): + if NTTY == max([x.ICT for x in self.content]): # CHECK FOR POSSIBLE ERROR self.NTTY = NTTY else: raise ValueError("IN MASSATOMTYPECODE NMATY is not the maximal Mass atom type code.") @@ -811,7 +915,7 @@ def __init__(self, content: Union[Iterable[angle_type], str], raise IOError("I don't understand the type of NMATY: " + str(type(NTTY))) def read_content_from_str(self, content: str): - if (isinstance(content, str)): + if isinstance(content, str): lines = content.split("\n") else: lines = content @@ -819,7 +923,7 @@ def read_content_from_str(self, content: str): table_start = 0 for line in lines: table_start += 1 - if (all([field in line for field in self.table_header])): + if all([field in line for field in self.table_header]): break if table_start == len(lines): @@ -827,31 +931,39 @@ def read_content_from_str(self, content: str): table_lines = lines[table_start:] for field in table_lines: - if (not field.strip().startswith("#") and not len(field.strip()) == 0): + if not field.strip().startswith("#") and not len(field.strip()) == 0: ICT, CT, CHT, T0 = field.strip().split() # nasty next line formatting of gromos comment_index = table_lines.index(field) + 1 - clean = re.sub('\(.*?\)', '', table_lines[comment_index]) + clean = re.sub("\(.*?\)", "", table_lines[comment_index]) split_line = [x for x in clean.replace("#", "").replace("-", "").strip().split(" ") if (len(x) > 0)] split_line = [x.split(",") if ("," in x) else x for x in split_line] - if (len(split_line) == 4): + if len(split_line) == 4: atomI, atomJ, atomK, specialNumber = split_line - elif (len(split_line) == 3): + elif len(split_line) == 3: atomI, atomJ, atomK = split_line specialNumber = 0 - params = angle_type(ICT=int(ICT), CT=float(CT), CHT=float(CHT), T0=float(T0), atomI=atomI, atomJ=atomJ, atomK=atomK, - specialNumber=int(specialNumber)) + params = angle_type( + ICT=int(ICT), + CT=float(CT), + CHT=float(CHT), + T0=float(T0), + atomI=atomI, + atomJ=atomJ, + atomK=atomK, + specialNumber=int(specialNumber), + ) self.content.append(params) def block_to_string(self) -> str: result = self.name + "\n" - result += "#"+self.field_seperator+"NRTTY"+self.field_seperator+"NTTY"+self.line_seperator - result += self.field_seperator+str(self.NRTTY)+self.field_seperator+str(self.NTTY)+self.line_seperator - result += "# TABLE CONTENT: "+self.line_seperator - result += "#"+self.field_seperator+self.field_seperator.join(self.table_header)+self.line_seperator + result += "#" + self.field_seperator + "NRTTY" + self.field_seperator + "NTTY" + self.line_seperator + result += self.field_seperator + str(self.NRTTY) + self.field_seperator + str(self.NTTY) + self.line_seperator + result += "# TABLE CONTENT: " + self.line_seperator + result += "#" + self.field_seperator + self.field_seperator.join(self.table_header) + self.line_seperator for x in self.content: result += x.to_string() result += "END\n" @@ -864,10 +976,14 @@ class TORSDIHEDRALTYPECODE(_iterable_topology_block): table_header: Iterable[str] = ["ICP(H)[N]", "CP[N]", "PD", "NP"] - def __init__(self, content: Union[Iterable[dihedral_type], str], - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None, - NRPTY: int = None, NPTY: int = None): + def __init__( + self, + content: Union[Iterable[dihedral_type], str], + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + NRPTY: int = None, + NPTY: int = None, + ): """ GROMOS (trigonometric) dihedral torsional angle parameters @@ -881,29 +997,29 @@ def __init__(self, content: Union[Iterable[dihedral_type], str], NPTY : int, optional Number of maximal dihedral-angle index.rst """ - super().__init__(FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, content = content) + super().__init__(FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, content=content) - if (isinstance(content, list) and all([isinstance(x, str) for x in content])): + if isinstance(content, list) and all([isinstance(x, str) for x in content]): self.read_content_from_str(content) - elif (isinstance(content, Iterable) and all([isinstance(x, atom_mass_type) for x in content])): + elif isinstance(content, Iterable) and all([isinstance(x, atom_mass_type) for x in content]): self.content = content else: raise IOError("I don't understand the type of content: " + str(type(content))) - if (NRPTY is None): + if NRPTY is None: self.NRPTY = len(self.content) - elif (isinstance(NRPTY, int)): - if (NRPTY == len(self.content)): # CHECK FOR POSSIBLE ERROR + elif isinstance(NRPTY, int): + if NRPTY == len(self.content): # CHECK FOR POSSIBLE ERROR self.NRPTY = NRPTY else: raise ValueError("IN MASSATOMTYPECODE NRMATY is not equal to the ammount of MASSATOMTYPES.") else: raise IOError("I don't understand the type of NRPTY: " + str(type(NRPTY))) - if (NPTY is None): + if NPTY is None: self.NPTY = max([x.ICP for x in self.content]) - elif (isinstance(NPTY, int)): - if (NPTY == max([x.ICP for x in self.content])): # CHECK FOR POSSIBLE ERROR + elif isinstance(NPTY, int): + if NPTY == max([x.ICP for x in self.content]): # CHECK FOR POSSIBLE ERROR self.NPTY = NPTY else: raise ValueError("IN MASSATOMTYPECODE NPTY is not the maximal Mass atom type code.") @@ -911,7 +1027,7 @@ def __init__(self, content: Union[Iterable[dihedral_type], str], raise IOError("I don't understand the type of NMATY: " + str(type(NPTY))) def read_content_from_str(self, content: str): - if (isinstance(content, str)): + if isinstance(content, str): lines = content.split("\n") else: lines = content @@ -919,55 +1035,67 @@ def read_content_from_str(self, content: str): table_start = 0 for line in lines: table_start += 1 - if (all([field in line for field in self.table_header])): + if all([field in line for field in self.table_header]): break if table_start == len(lines): - raise ValueError("Could not find the TABLE start in "+self.name) + raise ValueError("Could not find the TABLE start in " + self.name) table_lines = lines[table_start:] for field in table_lines: - if (not field.strip().startswith("#") and not len(field.strip()) == 0): + if not field.strip().startswith("#") and not len(field.strip()) == 0: ICP, CP, PD, NP = field.strip().split() # nasty next line formatting of gromos comment_index = table_lines.index(field) + 1 - clean = re.sub('\(.*?\)', '', table_lines[comment_index]) + clean = re.sub("\(.*?\)", "", table_lines[comment_index]) split_line = [x for x in clean.replace("#", "").strip().split(" ") if (len(x) > 0)] - #print("splits", split_line) + # print("splits", split_line) special_number = float(split_line[-1]) if (split_line[-1].isdigit()) else 0 atom_dihedral_string = ["X" if (len(x) == 0) else x for x in split_line[0].split("-")] - atom_dihedral_string = [["X" if (len(y) == 0) else y for y in x.split(",")] if ("," in x) else x for x - in atom_dihedral_string] - atom_dihedral_string = [x for x in split_line[0].split("-") if (len(x) > 0 and not x == "-") ] + atom_dihedral_string = [ + ["X" if (len(y) == 0) else y for y in x.split(",")] if ("," in x) else x + for x in atom_dihedral_string + ] + atom_dihedral_string = [x for x in split_line[0].split("-") if (len(x) > 0 and not x == "-")] - #print("Atoms-String: ", atom_dihedral_string) + # print("Atoms-String: ", atom_dihedral_string) - if (len(atom_dihedral_string) == 4): + if len(atom_dihedral_string) == 4: atomI, atomJ, atomK, atomL = atom_dihedral_string - elif(len(atom_dihedral_string) == 2): + elif len(atom_dihedral_string) == 2: atomI, atomJ, atomK, atomL = ["X"] + atom_dihedral_string + ["X"] - elif(len(atom_dihedral_string) == 1): + elif len(atom_dihedral_string) == 1: atomI, atomJ, atomK, atomL = ["X"] + atom_dihedral_string + ["X"] + ["X"] else: - #print(atom_dihedral_string) + # print(atom_dihedral_string) atomI, atomJ, atomK, atomL = atom_dihedral_string + ["X"] - concrete_example = table_lines[comment_index + 1] if ( - table_lines[comment_index + 1].startswith("#")) else "" - #print(concrete_example) - params = dihedral_type(ICP=int(ICP), CP=float(CP), PD=float(PD), NP=float(NP), - atomI=atomI, atomJ=atomJ, atomK=atomK, atomL=atomL, - special_number=int(special_number), concrete_example=concrete_example) + concrete_example = ( + table_lines[comment_index + 1] if (table_lines[comment_index + 1].startswith("#")) else "" + ) + # print(concrete_example) + params = dihedral_type( + ICP=int(ICP), + CP=float(CP), + PD=float(PD), + NP=float(NP), + atomI=atomI, + atomJ=atomJ, + atomK=atomK, + atomL=atomL, + special_number=int(special_number), + concrete_example=concrete_example, + ) self.content.append(params) def block_to_string(self) -> str: result = self.name + "\n" - result += "#"+self.field_seperator+"NRPTY"+self.field_seperator+"NPTY"+self.line_seperator - result += self.field_seperator+str(self.NRPTY)+self.field_seperator+str(self.NPTY)+self.line_seperator - result += "# TABLE CONTENT: "+self.line_seperator - result += "#"+self.field_seperator+self.field_seperator.join(self.table_header)+self.line_seperator + result += "#" + self.field_seperator + "NRPTY" + self.field_seperator + "NPTY" + self.line_seperator + result += self.field_seperator + str(self.NRPTY) + self.field_seperator + str(self.NPTY) + self.line_seperator + result += "# TABLE CONTENT: " + self.line_seperator + result += "#" + self.field_seperator + self.field_seperator.join(self.table_header) + self.line_seperator for x in self.content: result += x.to_string() result += "END\n" @@ -979,10 +1107,14 @@ class IMPDIHEDRALTYPECODE(_iterable_topology_block): NQTY: int table_header: Iterable[str] = ["ICQ", "CQ", "Q0"] - def __init__(self, content: Union[Iterable[improper_dihedral_type], str], - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None, - NRQTY: int = None, NQTY: int = None): + def __init__( + self, + content: Union[Iterable[improper_dihedral_type], str], + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + NRQTY: int = None, + NQTY: int = None, + ): """ GROMOS improper dihedral type parameters @@ -996,31 +1128,31 @@ def __init__(self, content: Union[Iterable[improper_dihedral_type], str], NQTY : int, optional Number of maximal improperDihedrals index.rst """ - super().__init__(FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, content = content) + super().__init__(FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, content=content) - if (isinstance(content, list) and all([isinstance(x, str) for x in content])): + if isinstance(content, list) and all([isinstance(x, str) for x in content]): self.read_content_from_str(content) - elif (isinstance(content, Iterable) and all([isinstance(x, atom_mass_type) for x in content])): + elif isinstance(content, Iterable) and all([isinstance(x, atom_mass_type) for x in content]): self.content = content else: raise IOError("I don't understand the type of content: " + str(type(content))) - #print(self.content) + # print(self.content) - if (NRQTY is None): + if NRQTY is None: self.NRQTY = len(self.content) - elif (isinstance(NRQTY, int)): - if (NRQTY == len(self.content)): # CHECK FOR POSSIBLE ERROR + elif isinstance(NRQTY, int): + if NRQTY == len(self.content): # CHECK FOR POSSIBLE ERROR self.NRQTY = NRQTY else: raise ValueError("IN MASSATOMTYPECODE NRQTY is not equal to the ammount of MASSATOMTYPES.") else: raise IOError("I don't understand the type of NRQTY: " + str(type(NRQTY))) - if (NQTY is None): + if NQTY is None: self.NQTY = max([x.ICQ for x in self.content]) - elif (isinstance(NQTY, int)): - if (NQTY == max([x.ICQ for x in self.content])): # CHECK FOR POSSIBLE ERROR + elif isinstance(NQTY, int): + if NQTY == max([x.ICQ for x in self.content]): # CHECK FOR POSSIBLE ERROR self.NQTY = NQTY else: raise ValueError("IN MASSATOMTYPECODE NQTY is not the maximal Mass atom type code.") @@ -1028,7 +1160,7 @@ def __init__(self, content: Union[Iterable[improper_dihedral_type], str], raise IOError("I don't understand the type of NQTY: " + str(type(NQTY))) def read_content_from_str(self, content: str): - if (isinstance(content, str)): + if isinstance(content, str): lines = content.split("\n") else: lines = content @@ -1036,7 +1168,7 @@ def read_content_from_str(self, content: str): table_start = 0 for line in lines: table_start += 1 - if (all([field in line for field in self.table_header])): + if all([field in line for field in self.table_header]): break if table_start == len(lines): @@ -1044,31 +1176,32 @@ def read_content_from_str(self, content: str): table_lines = lines[table_start:] for field in table_lines: - if (not field.strip().startswith("#") and not len(field.strip()) == 0): + if not field.strip().startswith("#") and not len(field.strip()) == 0: ICQ, CQ, Q0 = field.strip().split() # nasty next line formatting of gromos comment_index = table_lines.index(field) + 1 - clean = re.sub('\(.*?\)', '', table_lines[comment_index]) + clean = re.sub("\(.*?\)", "", table_lines[comment_index]) split_line = [x for x in clean.replace("#", "").replace("-", "").strip().split(" ") if (len(x) > 0)] split_line = [x.split(",") if ("," in x) else x for x in split_line] - if (len(split_line) == 3): + if len(split_line) == 3: groupType, special_number = " ".join(split_line[:2]), split_line[2] - elif (len(split_line) == 2): + elif len(split_line) == 2: groupType = split_line special_number = 0 - params = improper_dihedral_type(ICQ=int(ICQ), CQ=float(CQ), Q0=float(Q0), group_type=groupType, - special_number=int(special_number)) + params = improper_dihedral_type( + ICQ=int(ICQ), CQ=float(CQ), Q0=float(Q0), group_type=groupType, special_number=int(special_number) + ) self.content.append(params) def block_to_string(self) -> str: result = self.name + "\n" - result += "#"+self.field_seperator+"NRQTY"+self.field_seperator+"NQTY"+self.line_seperator - result += self.field_seperator+str(self.NRQTY)+self.field_seperator+str(self.NQTY)+self.line_seperator - result += "# TABLE CONTENT: "+self.line_seperator - result += "#"+self.field_seperator+self.field_seperator.join(self.table_header)+self.line_seperator + result += "#" + self.field_seperator + "NRQTY" + self.field_seperator + "NQTY" + self.line_seperator + result += self.field_seperator + str(self.NRQTY) + self.field_seperator + str(self.NQTY) + self.line_seperator + result += "# TABLE CONTENT: " + self.line_seperator + result += "#" + self.field_seperator + self.field_seperator.join(self.table_header) + self.line_seperator for x in self.content: result += x.to_string() result += "END\n" @@ -1078,9 +1211,14 @@ def block_to_string(self) -> str: class SINGLEATOMLJPAIR(_iterable_topology_block): NRATT: int table_header = ["IAC", "TYPE", "C6", "C12(1)", "C12(2)", "C12(3)"] - def __init__(self, content, NRATT: int = None, - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None, ): + + def __init__( + self, + content, + NRATT: int = None, + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + ): """ Parameters @@ -1090,19 +1228,19 @@ def __init__(self, content, NRATT: int = None, FORCEFIELD MAKETOPVERSION """ - super().__init__(FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, content = content) + super().__init__(FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, content=content) - if (isinstance(content, list) and all([isinstance(x, str) for x in content])): + if isinstance(content, list) and all([isinstance(x, str) for x in content]): self.read_content_from_str(content) - elif (isinstance(content, Iterable) and all([isinstance(x, atom_mass_type) for x in content])): + elif isinstance(content, Iterable) and all([isinstance(x, atom_mass_type) for x in content]): self.content = content else: raise IOError("I don't understand the type of content: " + str(type(content))) - if (NRATT is None): + if NRATT is None: self.NRATT = len(self.content) - elif (isinstance(NRATT, int)): - if (NRATT == len(self.content)): # CHECK FOR POSSIBLE ERROR + elif isinstance(NRATT, int): + if NRATT == len(self.content): # CHECK FOR POSSIBLE ERROR self.NRATT = NRATT else: raise ValueError("IN number of terms NRATT is not equal to the ammount of terms.") @@ -1110,7 +1248,7 @@ def __init__(self, content, NRATT: int = None, raise IOError("I don't understand the type of NRATT: " + str(type(NRATT))) def read_content_from_str(self, content: str): - if (isinstance(content, str)): + if isinstance(content, str): lines = content.split("\n") else: lines = content @@ -1118,7 +1256,7 @@ def read_content_from_str(self, content: str): table_start = 0 for line in lines: table_start += 1 - if (all([field in line for field in self.table_header])): + if all([field in line for field in self.table_header]): break if table_start == len(lines): @@ -1128,39 +1266,53 @@ def read_content_from_str(self, content: str): subblock_end = -1 end_string = "#--" for subblock_start, field in enumerate(table_lines): - if (not field.strip().startswith("#") and not len(field.strip()) == 0 and subblock_start >= subblock_end): - #print("START: ", field) + if not field.strip().startswith("#") and not len(field.strip()) == 0 and subblock_start >= subblock_end: + # print("START: ", field) IAC, TYPE, C6, C12_1, C12_2, C12_3 = field.strip().split() - IAC, TYPE, C6, C12_1, C12_2, C12_3 = [int(IAC), str(TYPE), float(C6), float(C12_1), float(C12_2), - float(C12_3)] + IAC, TYPE, C6, C12_1, C12_2, C12_3 = [ + int(IAC), + str(TYPE), + float(C6), + float(C12_1), + float(C12_2), + float(C12_3), + ] LJ14PAIR = [] subblock_lines = 0 secondCS = False - for subblock_line in table_lines[subblock_start + 1:]: + for subblock_line in table_lines[subblock_start + 1 :]: subblock_lines += 1 # print(subblock_line) - if (end_string in subblock_line): + if end_string in subblock_line: subblock_end = subblock_start + subblock_lines break - elif (not subblock_line.startswith("#") and not secondCS): + elif not subblock_line.startswith("#") and not secondCS: CS6, CS12 = list(map(float, subblock_line.strip().split())) secondCS = True - elif (not subblock_line.startswith("#") and subblock_lines > 2): + elif not subblock_line.startswith("#") and subblock_lines > 2: LJ14PAIR.append(list(map(int, subblock_line.split()))) - params = single_atom_lj_pair_type(IAC=IAC, TYPE=TYPE, - C6=C6, C12_1=C12_1, C12_2=C12_2, C12_3=C12_3, - CS6=CS6, CS12=CS12, LJ14PAIR=LJ14PAIR) + params = single_atom_lj_pair_type( + IAC=IAC, + TYPE=TYPE, + C6=C6, + C12_1=C12_1, + C12_2=C12_2, + C12_3=C12_3, + CS6=CS6, + CS12=CS12, + LJ14PAIR=LJ14PAIR, + ) # print(params) self.content.append(params) def block_to_string(self) -> str: result = self.name + "\n" - result += "#"+self.field_seperator+"NRATT" - result += self.field_seperator+str(self.NRATT)+self.line_seperator - result += "# TABLE CONTENT: "+self.line_seperator - result += "#"+self.field_seperator+self.field_seperator.join(self.table_header)+self.line_seperator + result += "#" + self.field_seperator + "NRATT" + result += self.field_seperator + str(self.NRATT) + self.line_seperator + result += "# TABLE CONTENT: " + self.line_seperator + result += "#" + self.field_seperator + self.field_seperator.join(self.table_header) + self.line_seperator for x in self.content: result += x.to_string() result += "END\n" @@ -1174,9 +1326,13 @@ class MIXEDATOMLJPAIR(_iterable_topology_block): GROMOS 43A1 normal van der Waals parameters for mixed atom type pairs (I,J) """ - def __init__(self, content, NRMTT: int = None, - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None, ): + def __init__( + self, + content, + NRMTT: int = None, + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + ): """ Parameters @@ -1186,19 +1342,19 @@ def __init__(self, content, NRMTT: int = None, FORCEFIELD MAKETOPVERSION """ - super().__init__(FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, content = content) + super().__init__(FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, content=content) - if (isinstance(content, list) and all([isinstance(x, str) for x in content])): + if isinstance(content, list) and all([isinstance(x, str) for x in content]): self.read_content_from_str(content) - elif (isinstance(content, Iterable) and all([isinstance(x, atom_mass_type) for x in content])): + elif isinstance(content, Iterable) and all([isinstance(x, atom_mass_type) for x in content]): self.content = content else: raise IOError("I don't understand the type of content: " + str(type(content))) - if (NRMTT is None): + if NRMTT is None: self.NRMTT = len(self.content) - elif (isinstance(NRMTT, int)): - if (NRMTT == len(self.content)): # CHECK FOR POSSIBLE ERROR + elif isinstance(NRMTT, int): + if NRMTT == len(self.content): # CHECK FOR POSSIBLE ERROR self.NRMTT = NRMTT else: raise ValueError("IN number of terms NRMTT is not equal to the ammount of terms.") @@ -1206,7 +1362,7 @@ def __init__(self, content, NRMTT: int = None, raise IOError("I don't understand the type of NRMTT: " + str(type(NRMTT))) def read_content_from_str(self, content: str): - if (isinstance(content, str)): + if isinstance(content, str): lines = content.split("\n") else: lines = content @@ -1214,26 +1370,33 @@ def read_content_from_str(self, content: str): for line in lines: table_start += 1 - if (all([field in line for field in self.table_header])): + if all([field in line for field in self.table_header]): break - if table_start == len(lines): #as there is no table header in the file + if table_start == len(lines): # as there is no table header in the file table_start = 0 table_lines = lines[table_start:] for field in table_lines: - if (not field.startswith("#")): + if not field.startswith("#"): IACI, IACJ, C6, C12_1, C12_2, C12_3 = field.strip().split() - self.content.append(mixed_atom_lj_pair_type(IACI=int(IACI), IACJ=int(IACJ), - C6=float(C6), C12_1=float(C12_1), C12_2=float(C12_2), C12_3=float(C12_3))) - + self.content.append( + mixed_atom_lj_pair_type( + IACI=int(IACI), + IACJ=int(IACJ), + C6=float(C6), + C12_1=float(C12_1), + C12_2=float(C12_2), + C12_3=float(C12_3), + ) + ) def block_to_string(self) -> str: result = self.name + "\n" - result += "#"+self.field_seperator+"NRMTT"+self.line_seperator - result += self.field_seperator+str(self.NRMTT)+self.line_seperator - result += "# TABLE CONTENT: "+self.line_seperator - result += "#"+self.field_seperator+self.field_seperator.join(self.table_header)+self.line_seperator + result += "#" + self.field_seperator + "NRMTT" + self.line_seperator + result += self.field_seperator + str(self.NRMTT) + self.line_seperator + result += "# TABLE CONTENT: " + self.line_seperator + result += "#" + self.field_seperator + self.field_seperator.join(self.table_header) + self.line_seperator for x in self.content: result += x.to_string() result += "END\n" @@ -1244,9 +1407,13 @@ class SPECATOMLJPAIR(_iterable_topology_block): NRST: int table_header: Iterable[str] = ["???"] - def __init__(self, content, NRST: int = None, - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None, ): + def __init__( + self, + content, + NRST: int = None, + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + ): """ Parameters @@ -1256,19 +1423,19 @@ def __init__(self, content, NRST: int = None, FORCEFIELD MAKETOPVERSION """ - super().__init__(FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, content = content) + super().__init__(FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, content=content) - if (isinstance(content, list) and all([isinstance(x, str) for x in content])): + if isinstance(content, list) and all([isinstance(x, str) for x in content]): self.read_content_from_str(content) - elif (isinstance(content, Iterable) and all([isinstance(x, atom_mass_type) for x in content])): + elif isinstance(content, Iterable) and all([isinstance(x, atom_mass_type) for x in content]): self.content = content else: raise IOError("I don't understand the type of content: " + str(type(content))) - if (NRST is None): + if NRST is None: self.NRST = len(self.content) - elif (isinstance(NRST, int)): - if (NRST == len(self.content)): # CHECK FOR POSSIBLE ERROR + elif isinstance(NRST, int): + if NRST == len(self.content): # CHECK FOR POSSIBLE ERROR self.NRST = NRST else: raise ValueError("IN number of terms NRST is not equal to the ammount of terms.") @@ -1276,16 +1443,31 @@ def __init__(self, content, NRST: int = None, raise IOError("I don't understand the type of NRST: " + str(type(NRST))) def read_content_from_str(self, content: str): - #TODO: implement - #warnings.warn("SPECIAL LJ BLOCK IS NOT IMPLEMENTED!") + # TODO: implement + # warnings.warn("SPECIAL LJ BLOCK IS NOT IMPLEMENTED!") return [] + ################################################################### # Top() class blocks ################################################################### + class soluteatom_type(_generic_field): - def __init__(self, ATNM: int, MRES: int, PANM: str, IAC: int, MASS: float, CG: float, CGC: int, INE: int, INEvalues, INE14: int, INE14values): + def __init__( + self, + ATNM: int, + MRES: int, + PANM: str, + IAC: int, + MASS: float, + CG: float, + CGC: int, + INE: int, + INEvalues, + INE14: int, + INE14values, + ): """soluteatom_type Parameters @@ -1326,12 +1508,29 @@ def __init__(self, ATNM: int, MRES: int, PANM: str, IAC: int, MASS: float, CG: f self.INE14values = INE14values def to_string(self): - str_line = "\t" + str(self.ATNM) + "\t" + str(self.MRES) + "\t" + str(self.PANM) + "\t" + str(self.IAC) + "\t" + str(self.MASS) + "\t" + str(self.CG) + "\t" + str(self.CGC) + "\t" + str(self.INE) + str_line = ( + "\t" + + str(self.ATNM) + + "\t" + + str(self.MRES) + + "\t" + + str(self.PANM) + + "\t" + + str(self.IAC) + + "\t" + + str(self.MASS) + + "\t" + + str(self.CG) + + "\t" + + str(self.CGC) + + "\t" + + str(self.INE) + ) lcounter = 0 for iter in self.INEvalues: str_line += "\t" + str(iter).strip() lcounter += 1 - if (lcounter % 6) == 0 and len(self.INEvalues)>6: + if (lcounter % 6) == 0 and len(self.INEvalues) > 6: str_line += "\n\t\t\t\t\t\t\t\t\t\t" str_line += "\n\t\t\t\t\t\t\t\t\t\t" + str(self.INE14) for iter in self.INE14values: @@ -1341,7 +1540,7 @@ def to_string(self): class bondstretchtype_type(_generic_field): - def __init__(self, CB: float, CHB:float, B0: float): + def __init__(self, CB: float, CHB: float, B0: float): """ GROMOS bondstretchtype for a single pair @@ -1359,11 +1558,14 @@ def __init__(self, CB: float, CHB:float, B0: float): self.B0 = B0 def to_string(self): - str_line = "\t" + "{:.5e}".format(self.CB) + "\t" + "{:.5e}".format(self.CHB) + "\t" + "{:.5e}".format(self.B0) +"\n" + str_line = ( + "\t" + "{:.5e}".format(self.CB) + "\t" + "{:.5e}".format(self.CHB) + "\t" + "{:.5e}".format(self.B0) + "\n" + ) return str_line + class bondanglebendtype_type(_generic_field): - def __init__(self, CT: float, CHT:float, T0: float): + def __init__(self, CT: float, CHT: float, T0: float): """ GROMOS bondanglebendtype for a single angle @@ -1381,7 +1583,9 @@ def __init__(self, CT: float, CHT:float, T0: float): self.T0 = T0 def to_string(self): - str_line = "\t" + "{:.5e}".format(self.CT) + "\t" + "{:.5e}".format(self.CHT) + "\t" + "{:.5e}".format(self.T0) +"\n" + str_line = ( + "\t" + "{:.5e}".format(self.CT) + "\t" + "{:.5e}".format(self.CHT) + "\t" + "{:.5e}".format(self.T0) + "\n" + ) return str_line @@ -1404,7 +1608,7 @@ def __init__(self, IB: int, JB: int, ICB: int): self.ICB = ICB def to_string(self): - str_line = "\t" + str(self.IB) + "\t" + str(self.JB) + "\t" + str(self.ICB) +"\n" + str_line = "\t" + str(self.IB) + "\t" + str(self.JB) + "\t" + str(self.ICB) + "\n" return str_line @@ -1430,9 +1634,10 @@ def __init__(self, IT: int, JT: int, KT: int, ICT: int): self.ICT = ICT def to_string(self): - str_line = "\t" + str(self.IT) + "\t" + str(self.JT) + "\t" + str(self.KT) + "\t" + str(self.ICT) +"\n" + str_line = "\t" + str(self.IT) + "\t" + str(self.JT) + "\t" + str(self.KT) + "\t" + str(self.ICT) + "\n" return str_line + class impdihedraltype_type(_generic_field): def __init__(self, CQ: float, Q0: float): """ @@ -1452,8 +1657,9 @@ def to_string(self): str_line = "\t" + "{:.5e}".format(self.CQ) + "\t" + "{:.5e}".format(self.Q0) + "\n" return str_line + class impdihedralh_type(_generic_field): - def __init__(self, IQH:int, JQH:int, KQH:int, LQH:int, ICQH:int ): + def __init__(self, IQH: int, JQH: int, KQH: int, LQH: int, ICQH: int): """ GROMOS impdihedralH for a single pair @@ -1464,9 +1670,9 @@ def __init__(self, IQH:int, JQH:int, KQH:int, LQH:int, ICQH:int ): KQH:int LQH:int IQH,JQH,KQH,LQH: atom sequence numbers of atoms forming an improper dihedral - ICQH:int + ICQH:int improper dihedral type code - + """ self.IQH = IQH self.JQH = JQH @@ -1475,11 +1681,24 @@ def __init__(self, IQH:int, JQH:int, KQH:int, LQH:int, ICQH:int ): self.ICQH = ICQH def to_string(self): - str_line = "\t" + str(self.IQH) + "\t" + str(self.JQH) + "\t" + str(self.KQH) + "\t" + str(self.LQH) + "\t" + str(self.ICQH) + "\n" + str_line = ( + "\t" + + str(self.IQH) + + "\t" + + str(self.JQH) + + "\t" + + str(self.KQH) + + "\t" + + str(self.LQH) + + "\t" + + str(self.ICQH) + + "\n" + ) return str_line + class impdihedral_type(_generic_field): - def __init__(self, IQ:int, JQ:int, KQ:int, LQ:int, ICQ:int ): + def __init__(self, IQ: int, JQ: int, KQ: int, LQ: int, ICQ: int): """ GROMOS impdihedral for a single pair @@ -1490,9 +1709,9 @@ def __init__(self, IQ:int, JQ:int, KQ:int, LQ:int, ICQ:int ): KQ:int LQ:int IQ,JQ,KQ,LQ: atom sequence numbers of atoms forming an improper dihedral - ICQ:int + ICQ:int improper dihedral type code - + """ self.IQ = IQ self.JQ = JQ @@ -1501,11 +1720,24 @@ def __init__(self, IQ:int, JQ:int, KQ:int, LQ:int, ICQ:int ): self.ICQ = ICQ def to_string(self): - str_line = "\t" + str(self.IQ) + "\t" + str(self.JQ) + "\t" + str(self.KQ) + "\t" + str(self.LQ) + "\t" + str(self.ICQ) + "\n" + str_line = ( + "\t" + + str(self.IQ) + + "\t" + + str(self.JQ) + + "\t" + + str(self.KQ) + + "\t" + + str(self.LQ) + + "\t" + + str(self.ICQ) + + "\n" + ) return str_line + class torsdihedraltype_type(_generic_field): - def __init__(self, CP:float, PD:float, NP:int): + def __init__(self, CP: float, PD: float, NP: int): """ GROMOS dihedraltype for a single pair @@ -1515,8 +1747,8 @@ def __init__(self, CP:float, PD:float, NP:int): force constant PD:float phase-shift angle - NP:int - multiplicity + NP:int + multiplicity """ self.CP = CP self.PD = PD @@ -1526,13 +1758,14 @@ def to_string(self): str_line = "\t" + "{:.5e}".format(self.CP) + "\t" + "{:.5e}".format(self.PD) + "\t" + str(self.NP) + "\n" return str_line + class dihedralh_type(_generic_field): - def __init__(self, IPH:int, JPH:int, KPH:int, LPH:int, ICPH:int): + def __init__(self, IPH: int, JPH: int, KPH: int, LPH: int, ICPH: int): """ GROMOS dihedral for a single pair Parameters - ---------- + ---------- """ self.IPH = IPH self.JPH = JPH @@ -1541,16 +1774,29 @@ def __init__(self, IPH:int, JPH:int, KPH:int, LPH:int, ICPH:int): self.ICPH = ICPH def to_string(self): - str_line = "\t" + str(self.IPH) + "\t" + str(self.JPH) + "\t" + str(self.KPH) + "\t" + str(self.LPH) + "\t" + str(self.ICPH) + "\n" + str_line = ( + "\t" + + str(self.IPH) + + "\t" + + str(self.JPH) + + "\t" + + str(self.KPH) + + "\t" + + str(self.LPH) + + "\t" + + str(self.ICPH) + + "\n" + ) return str_line + class top_dihedral_type(_generic_field): - def __init__(self, IP:int, JP:int, KP:int, LP:int, ICP:int): + def __init__(self, IP: int, JP: int, KP: int, LP: int, ICP: int): """ GROMOS dihedral for a single pair Parameters - ---------- + ---------- """ self.IP = IP self.JP = JP @@ -1559,11 +1805,24 @@ def __init__(self, IP:int, JP:int, KP:int, LP:int, ICP:int): self.ICP = ICP def to_string(self): - str_line = "\t" + str(self.IP) + "\t" + str(self.JP) + "\t" + str(self.KP) + "\t" + str(self.LP) + "\t" + str(self.ICP) + "\n" + str_line = ( + "\t" + + str(self.IP) + + "\t" + + str(self.JP) + + "\t" + + str(self.KP) + + "\t" + + str(self.LP) + + "\t" + + str(self.ICP) + + "\n" + ) return str_line + class crossgihedralh_type(_generic_field): - def __init__(self, APH:int, BPH:int, CPH:int, DPH:int, EPH:int, FPH:int, GPH:int, HPH:int, ICCH:int): + def __init__(self, APH: int, BPH: int, CPH: int, DPH: int, EPH: int, FPH: int, GPH: int, HPH: int, ICCH: int): """ GROMOS Cross Dihedral type for H @@ -1600,11 +1859,32 @@ def __init__(self, APH:int, BPH:int, CPH:int, DPH:int, EPH:int, FPH:int, GPH:int self.ICCH = ICCH def to_string(self): - str_line = "\t" + str(self.APH) + "\t" + str(self.BPH) + "\t" + str(self.CPH) + "\t" + str(self.DPH) + "\t" + str(self.EPH) + "\t" + str(self.FPH) + "\t" + str(self.GPH) + "\t" + str(self.HPH) + "\t" + str(self.ICCH) + "\n" + str_line = ( + "\t" + + str(self.APH) + + "\t" + + str(self.BPH) + + "\t" + + str(self.CPH) + + "\t" + + str(self.DPH) + + "\t" + + str(self.EPH) + + "\t" + + str(self.FPH) + + "\t" + + str(self.GPH) + + "\t" + + str(self.HPH) + + "\t" + + str(self.ICCH) + + "\n" + ) return str_line + class crossgihedral_type(_generic_field): - def __init__(self, AP:int, BP:int, CP:int, DP:int, EP:int, FP:int, GP:int, HP:int, ICC:int): + def __init__(self, AP: int, BP: int, CP: int, DP: int, EP: int, FP: int, GP: int, HP: int, ICC: int): """ GROMOS Cross Dihedral type for NON H Atoms @@ -1641,16 +1921,37 @@ def __init__(self, AP:int, BP:int, CP:int, DP:int, EP:int, FP:int, GP:int, HP:in self.ICC = ICC def to_string(self): - str_line = "\t" + str(self.AP) + "\t" + str(self.BP) + "\t" + str(self.CP) + "\t" + str(self.DP) + "\t" + str(self.EP) + "\t" + str(self.FP) + "\t" + str(self.GP) + "\t" + str(self.HP) + "\t" + str(self.ICC) + "\n" + str_line = ( + "\t" + + str(self.AP) + + "\t" + + str(self.BP) + + "\t" + + str(self.CP) + + "\t" + + str(self.DP) + + "\t" + + str(self.EP) + + "\t" + + str(self.FP) + + "\t" + + str(self.GP) + + "\t" + + str(self.HP) + + "\t" + + str(self.ICC) + + "\n" + ) return str_line + class ljparameters_type(_generic_field): - def __init__(self, IAC:int, JAC:int, C12:float, C6:float, CS12:float, CS6:float): + def __init__(self, IAC: int, JAC: int, C12: float, C6: float, CS12: float, CS6: float): """ GROMOS LJ parameter pair Parameters - ---------- + ---------- """ self.IAC = IAC self.JAC = JAC @@ -1660,16 +1961,31 @@ def __init__(self, IAC:int, JAC:int, C12:float, C6:float, CS12:float, CS6:float) self.CS6 = CS6 def to_string(self): - str_line = "\t" + str(self.IAC) + "\t" + str(self.JAC) + "\t" + "{:.6e}".format(self.C12) + "\t" + "{:.6e}".format(self.C6) + "\t" + "{:.6e}".format(self.CS12) + "\t" + "{:.6e}".format(self.CS6) + "\n" + str_line = ( + "\t" + + str(self.IAC) + + "\t" + + str(self.JAC) + + "\t" + + "{:.6e}".format(self.C12) + + "\t" + + "{:.6e}".format(self.C6) + + "\t" + + "{:.6e}".format(self.CS12) + + "\t" + + "{:.6e}".format(self.CS6) + + "\n" + ) return str_line + class ljexception_type(_generic_field): - def __init__(self, AT1:int, AT2:int, C12:float, C6:float): + def __init__(self, AT1: int, AT2: int, C12: float, C6: float): """ GROMOS LJ exception pair Parameters - ---------- + ---------- """ self.AT1 = AT1 self.AT2 = AT2 @@ -1677,16 +1993,27 @@ def __init__(self, AT1:int, AT2:int, C12:float, C6:float): self.C6 = C6 def to_string(self): - str_line = "\t" + str(self.AT1) + "\t" + str(self.AT2) + "\t" + "{:.6e}".format(self.C12) + "\t" + "{:.6e}".format(self.C6) + "\n" + str_line = ( + "\t" + + str(self.AT1) + + "\t" + + str(self.AT2) + + "\t" + + "{:.6e}".format(self.C12) + + "\t" + + "{:.6e}".format(self.C6) + + "\n" + ) return str_line + class solventatom_type(_generic_field): - def __init__(self, I:int, ANMS:str, IACS:int, MASS:float, CGS:float): + def __init__(self, I: int, ANMS: str, IACS: int, MASS: float, CGS: float): """ GROMOS solventatom line Parameters - ---------- + ---------- """ self.I = I self.ANMS = ANMS @@ -1695,16 +2022,29 @@ def __init__(self, I:int, ANMS:str, IACS:int, MASS:float, CGS:float): self.CGS = CGS def to_string(self): - str_line = "\t" + str(self.I) + "\t" + str(self.ANMS) + "\t" + str(self.IACS) + "\t" + "{:.5e}".format(self.MASS) + "\t" + "{:.5e}".format(self.CGS) +"\n" + str_line = ( + "\t" + + str(self.I) + + "\t" + + str(self.ANMS) + + "\t" + + str(self.IACS) + + "\t" + + "{:.5e}".format(self.MASS) + + "\t" + + "{:.5e}".format(self.CGS) + + "\n" + ) return str_line + class solventconstr_type(_generic_field): - def __init__(self, ICONS:int, JCONS:int, CONS:float): + def __init__(self, ICONS: int, JCONS: int, CONS: float): """ GROMOS SOLVENTCONSTR entry Parameters - ---------- + ---------- """ self.ICONS = ICONS self.JCONS = JCONS @@ -1714,8 +2054,9 @@ def to_string(self): str_line = "\t" + str(self.ICONS) + "\t" + str(self.JCONS) + "\t" + str(self.CONS) + "\n" return str_line + class constraint_type(_generic_field): - def __init__(self, IC:int, JC:int, ICC:float): + def __init__(self, IC: int, JC: int, ICC: float): """[summary] Parameters @@ -1730,20 +2071,31 @@ def __init__(self, IC:int, JC:int, ICC:float): self.IC = IC self.JC = JC self.ICC = ICC - + def to_string(self): - str_line = self.fieldseperator + str(self.IC) + self.fieldseperator + str(self.JC) + self.fieldseperator + str(self.ICC) + self.lineseperator + str_line = ( + self.fieldseperator + + str(self.IC) + + self.fieldseperator + + str(self.JC) + + self.fieldseperator + + str(self.ICC) + + self.lineseperator + ) return str_line class _topology_table_block(_iterable_topology_block): - table_header:Iterable[str] + table_header: Iterable[str] table_line_type = _generic_field - def __init__(self, content:(str or dict or None), - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None, - **kwargs): + def __init__( + self, + content: (str or dict or None), + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + **kwargs + ): """ Parent class for all table like GROMOS topolgy blocks. Offers a standard implementation of read and write functions @@ -1761,51 +2113,51 @@ def __init__(self, content:(str or dict or None), MAKETOPVERSION : MAKETOPVERSION, optional [description], by default None """ - #set attributes + # set attributes for attribute in vars(__class__): - if(attribute.isupper()): #is_allcapital()): + if attribute.isupper(): # is_allcapital()): setattr(self, attribute, kwargs[attribute]) - #init _iterable_topology_block + # init _iterable_topology_block super().__init__(FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, content=content) - - if len(kwargs.keys()) == 1 : + + if len(kwargs.keys()) == 1: for key, value in kwargs.items(): - if (value is None): + if value is None: setattr(self, key, len(self.content)) - elif (isinstance(value, int)): - if (value == len(self.content)): # CHECK FOR POSSIBLE ERROR + elif isinstance(value, int): + if value == len(self.content): # CHECK FOR POSSIBLE ERROR setattr(self, key, value) else: raise ValueError("In " + self.name + " is " + str(key) + " not equal to the ammount.") else: raise IOError("I don't understand the type of " + str(key) + ": " + str(type(key))) - - def _check_import_method(self, content:str=None): - if (isinstance(content, list) and all([isinstance(x, str) for x in content])): + + def _check_import_method(self, content: str = None): + if isinstance(content, list) and all([isinstance(x, str) for x in content]): self.read_content_from_str(content) - elif (isinstance(content, Iterable) and all([isinstance(x, type(self.table_line_type)) for x in content])): + elif isinstance(content, Iterable) and all([isinstance(x, type(self.table_line_type)) for x in content]): self.content = content - elif (isinstance(content, str)): + elif isinstance(content, str): self.read_content_from_str(content.split(self.line_seperator)) else: raise IOError("I don't understand the type of content: " + str(type(content))) - + def read_content_from_str(self, content: str): - if(not hasattr(self, "table_header")): - raise Exception("Could not find table_header of " + self.name) - elif(not hasattr(self, "table_line_type")): - raise Exception("Could not find table_line_type of " + self.name) + if not hasattr(self, "table_header"): + raise Exception("Could not find table_header of " + self.name) + elif not hasattr(self, "table_line_type"): + raise Exception("Could not find table_line_type of " + self.name) else: - if (isinstance(content, str)): + if isinstance(content, str): lines = content.split("\n") else: lines = content - #Table Reading: + # Table Reading: table_start = 0 for line in lines: table_start += 1 - if (all([field in line for field in self.table_header])): + if all([field in line for field in self.table_header]): break if table_start > len(lines): @@ -1813,80 +2165,84 @@ def read_content_from_str(self, content: str): else: self._read_table(lines[table_start:]) - def _read_table(self, table:str): + def _read_table(self, table: str): # get information of the needed structure of the sub class signature = inspect.signature(self.table_line_type.__init__) - parameter_name = [name for name in signature.parameters if(name != "self")] - parameter_type = {name:signature.parameters[name].annotation for name in parameter_name} + parameter_name = [name for name in signature.parameters if (name != "self")] + parameter_type = {name: signature.parameters[name].annotation for name in parameter_name} # loop over the table (=content) to create the sub classes (=table_line_type) for table_line in table: - if(not (table_line.startswith("#") or len(table_line)==0)): - # pre parse all non-empty non-comment lines into a list of strings - fields = table_line.strip().split() - if(len(fields) != len(parameter_name)): - raise Exception("Fields are not matching the ammount of needed arguments!\n " - "#fileds: " + str(len(fields)) + "\t#args: " + str(len(parameter_name))+"\n\n " - "require: "+str(parameter_name)+"\t got: "+str(fields)) - #generate arguments dict for line parsing (= table_line_type class construction) - kwargs={key: parameter_type[key](field) for key, field in zip(parameter_name, fields)} - self.content.append(self.table_line_type(**kwargs)) + if not (table_line.startswith("#") or len(table_line) == 0): + # pre parse all non-empty non-comment lines into a list of strings + fields = table_line.strip().split() + if len(fields) != len(parameter_name): + raise Exception( + "Fields are not matching the ammount of needed arguments!\n " + "#fileds: " + str(len(fields)) + "\t#args: " + str(len(parameter_name)) + "\n\n " + "require: " + str(parameter_name) + "\t got: " + str(fields) + ) + # generate arguments dict for line parsing (= table_line_type class construction) + kwargs = {key: parameter_type[key](field) for key, field in zip(parameter_name, fields)} + self.content.append(self.table_line_type(**kwargs)) pass def block_to_string(self) -> str: - result = "#"+self.field_seperator+self.field_seperator.join(self.table_header)+self.line_seperator + result = "#" + self.field_seperator + self.field_seperator.join(self.table_header) + self.line_seperator for x in self.content: result += x.to_string() return result class PHYSICALCONSTANTS(_topology_block): - def __init__(self, content:(str or dict or None or __class__), - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None): - #Default definition of physical constants + def __init__( + self, + content: (str or dict or None or __class__), + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + ): + # Default definition of physical constants self.FPEPSI = 138.9354 self.HBAR = 0.0635078 self.SPDL = 299792.458 self.BOLTZ = 0.00831441 - super().__init__(FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, content = content) - + super().__init__(FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, content=content) - def _check_import_method(self, content:str = None): - #elif (type(content) == __class__): + def _check_import_method(self, content: str = None): + # elif (type(content) == __class__): # self.content = content if content == [[""]] or content == [""] or content == None: self.content = [self.FPEPSI, self.HBAR, self.SPDL, self.BOLTZ] - elif (isinstance(content, list) and all([isinstance(x, str) for x in content])): + elif isinstance(content, list) and all([isinstance(x, str) for x in content]): self.read_content_from_str(content) - elif (isinstance(content, str)): + elif isinstance(content, str): self.read_content_from_str(content.split(self.line_seperator)) - elif (isinstance(content, tuple) and len(content)==4): + elif isinstance(content, tuple) and len(content) == 4: self.FPEPSI, self.HBAR, self.SPDL, self.BOLTZ = content self.content = [self.FPEPSI, self.HBAR, self.SPDL, self.BOLTZ] else: raise IOError("I don't understand the type of content: " + str(type(content))) def read_content_from_str(self, content: str): - if (isinstance(content, str)): + if isinstance(content, str): lines = content.split("\n") else: lines = content stash = [] for field in lines: - if (not field.strip().startswith("#") and not len(field.strip()) == 0): + if not field.strip().startswith("#") and not len(field.strip()) == 0: stash.append(float(field.strip())) - if(len(stash) >= 4): + if len(stash) >= 4: self.FPEPSI = stash[0] self.HBAR = stash[1] self.SPDL = stash[2] self.BOLTZ = stash[3] self.content = (self.FPEPSI, self.HBAR, self.SPDL, self.BOLTZ) - elif(len(stash) == 0): + elif len(stash) == 0: self.content = (self.FPEPSI, self.HBAR, self.SPDL, self.BOLTZ) else: raise IOError("Not enough arguments provided in PHYSICALCONSTANTS") - + def block_to_string(self) -> str: result = self.name + "\n" result += "# FPEPSI: 1.0/(4.0*PI*EPS0) (EPS0 is the permittivity of vacuum)" + self.line_seperator @@ -1900,49 +2256,66 @@ def block_to_string(self) -> str: result += "END\n" return result + class TOPVERSION(_topology_block): - def __init__(self, content:(str or dict or None or __class__), - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None): + def __init__( + self, + content: (str or dict or None or __class__), + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + ): super().__init__(FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, content=content) + class ATOMTYPENAME(_topology_block): - def __init__(self, content:(str or dict or None or __class__), - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None): + def __init__( + self, + content: (str or dict or None or __class__), + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + ): super().__init__(FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, content=content) + class RESNAME(_topology_block): - def __init__(self, content:(str or dict or None or __class__), - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None): - super().__init__(FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, content = content) + def __init__( + self, + content: (str or dict or None or __class__), + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + ): + super().__init__(FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, content=content) + class SOLUTEATOM(_iterable_topology_block): NRP: int table_header: Iterable[str] = ["IB", "JB", "ICB"] - def __init__(self, content:(str or dict or None or type(SOLUTEATOM)), - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None): - super().__init__(FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, content = content) - - def _check_import_method(self, content = None): - if (isinstance(content, list) and all([isinstance(x, str) for x in content])): + + def __init__( + self, + content: (str or dict or None or type(SOLUTEATOM)), + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + ): + super().__init__(FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, content=content) + + def _check_import_method(self, content=None): + if isinstance(content, list) and all([isinstance(x, str) for x in content]): self.read_content_from_str(content) - elif (type(content) == __class__): + elif type(content) == __class__: self.content = content - elif (content is __class__): + elif content is __class__: self.content = content def read_content_from_str(self, content: str): contentLines = [] - if (isinstance(content, str)): + if isinstance(content, str): lines = content.split("\n") else: lines = content - + for field in lines: - if (not field.strip().startswith("#") and not len(field.strip()) == 0): + if not field.strip().startswith("#") and not len(field.strip()) == 0: contentLines.append(field) # set NRP and check for sanity @@ -1950,59 +2323,93 @@ def read_content_from_str(self, content: str): self.NRP = int(contentLines.pop(0)) except: self.NRP = 0 - if(self.NRP < 0): - raise IOError ("NPR in SOLUTEATOM Block is " + str(self.NRP)) - elif(self.NRP == 0): + if self.NRP < 0: + raise IOError("NPR in SOLUTEATOM Block is " + str(self.NRP)) + elif self.NRP == 0: content = None - else: - for _ in range(self.NRP): # main import loop + else: + for _ in range(self.NRP): # main import loop dump1 = contentLines.pop(0).strip().split() - if(len(dump1) < 8): + if len(dump1) < 8: raise IOError("Not enough arguments provided in SOLUTEATOM Block") else: ATNM, MRES, PANM, IAC, MASS, CG, CGC, INE = dump1[0:8] - if(1 <= int(INE)): + if 1 <= int(INE): INEvalues = [int(i) for i in dump1[8:]] # keep reading in lines until we have all the data needed. - while (int(INE) > len(INEvalues)): + while int(INE) > len(INEvalues): try: - if (len(contentLines) == 0): - raise IOError("Not enough lines provided for multi line INE in SOLUTEATOM Block\nATNM="+str(ATNM)+" MRES="+str(MRES)) - elif any(i in contentLines[0] for i in ["\t\t\t\t\t"," "]): + if len(contentLines) == 0: + raise IOError( + "Not enough lines provided for multi line INE in SOLUTEATOM Block\nATNM=" + + str(ATNM) + + " MRES=" + + str(MRES) + ) + elif any(i in contentLines[0] for i in ["\t\t\t\t\t", " "]): INEvalues.extend([int(i) for i in contentLines.pop(0).strip().split()]) else: - raise IOError("no intendation detected for mult line INE in SOLUTEATOM Block or too large number for INE\nATNM="+str(ATNM)+" MRES="+str(MRES)) + raise IOError( + "no intendation detected for mult line INE in SOLUTEATOM Block or too large number for INE\nATNM=" + + str(ATNM) + + " MRES=" + + str(MRES) + ) except: - raise IOError("Problem reading INE for ATNM="+str(ATNM)+" MRES="+str(MRES)) + raise IOError("Problem reading INE for ATNM=" + str(ATNM) + " MRES=" + str(MRES)) break else: INEvalues = [] dump2 = contentLines.pop(0).strip().split() - if(len(dump2) < 1): - raise IOError("Not enough arguments provided in SOLUTEATOM Block\nATNM="+str(ATNM)+" MRES="+str(MRES)) + if len(dump2) < 1: + raise IOError( + "Not enough arguments provided in SOLUTEATOM Block\nATNM=" + str(ATNM) + " MRES=" + str(MRES) + ) else: INE14 = dump2[0] - if(1 <= int(INE14)): + if 1 <= int(INE14): INE14values = [int(i) for i in dump2[1:]] # keep reading in lines until we have all the data needed. - while (int(INE14) > len(INE14values)): + while int(INE14) > len(INE14values): try: - if (len(contentLines) == 0): - raise IOError("Not enough lines provided for multi line INE14 in SOLUTEATOM Block\nATNM="+str(ATNM)+" MRES="+str(MRES)) - elif any(i in contentLines[0] for i in ["\t\t\t\t\t"," "]): + if len(contentLines) == 0: + raise IOError( + "Not enough lines provided for multi line INE14 in SOLUTEATOM Block\nATNM=" + + str(ATNM) + + " MRES=" + + str(MRES) + ) + elif any(i in contentLines[0] for i in ["\t\t\t\t\t", " "]): INE14values.extend([int(i) for i in contentLines.pop(0).strip().split()]) else: - raise IOError("no intendation detected for mult line INE14 in SOLUTEATOM Block or too large number for INE14\nATNM="+str(ATNM)+" MRES="+str(MRES)) + raise IOError( + "no intendation detected for mult line INE14 in SOLUTEATOM Block or too large number for INE14\nATNM=" + + str(ATNM) + + " MRES=" + + str(MRES) + ) except: - raise IOError("Problem reading INE14 for ATNM="+str(ATNM)+" MRES="+str(MRES)) + raise IOError("Problem reading INE14 for ATNM=" + str(ATNM) + " MRES=" + str(MRES)) break else: INE14values = [] # pass everything to the subclass maker - params = soluteatom_type(int(ATNM), int(MRES), PANM, int(IAC), float(MASS), float(CG), int(CGC), int(INE), INEvalues, int(INE14), INE14values) + params = soluteatom_type( + int(ATNM), + int(MRES), + PANM, + int(IAC), + float(MASS), + float(CG), + int(CGC), + int(INE), + INEvalues, + int(INE14), + INE14values, + ) self.content.append(params) - + def block_to_string(self) -> str: result = self.name + self.line_seperator result += "# NRP: number of solute atoms" + self.line_seperator @@ -2013,15 +2420,19 @@ def block_to_string(self) -> str: result += "END\n" return result + class BONDSTRETCHTYPE(_topology_table_block): NBTY: int table_header: Iterable[str] = ["CB", "CHB", "B0"] table_line_type = bondstretchtype_type - - def __init__(self, content: Union[Iterable[bondstretchtype_type], str], - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None, - NBTY = None): + + def __init__( + self, + content: Union[Iterable[bondstretchtype_type], str], + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + NBTY=None, + ): """ GROMOS BONDSTRETCHTYPE block @@ -2033,10 +2444,12 @@ def __init__(self, content: Union[Iterable[bondstretchtype_type], str], NBTY : int, optional Number of bondstretchtypes """ - kwargs = {"NBTY" : NBTY} + kwargs = {"NBTY": NBTY} super().__init__(content=content, FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, **kwargs) + def read_content_from_str(self, content: str): super().read_content_from_str(content) + def block_to_string(self) -> str: result = self.name + "\n" result += "#" + self.field_seperator + "NBTY: number of covalent bond types" + self.line_seperator @@ -2046,16 +2459,18 @@ def block_to_string(self) -> str: return result - class BOND(_topology_table_block): - NBON:int = 1 + NBON: int = 1 table_header: Iterable[str] = ["IB", "JB", "ICB"] table_line_type = top_bond_type - def __init__(self, content: Union[Iterable[top_bond_type], str], - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None, - NBON = None): + def __init__( + self, + content: Union[Iterable[top_bond_type], str], + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + NBON=None, + ): """ GROMOS BOND block @@ -2067,27 +2482,35 @@ def __init__(self, content: Union[Iterable[top_bond_type], str], NBON : int, optional Number of bonds """ - kwargs = {"NBON" : NBON} + kwargs = {"NBON": NBON} super().__init__(content=content, FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, **kwargs) + def read_content_from_str(self, content: str): super().read_content_from_str(content) + def block_to_string(self) -> str: result = self.name + "\n" - result += "#" + self.field_seperator + "NBON: number of bonds NOT involving H atoms in solute" + self.line_seperator + result += ( + "#" + self.field_seperator + "NBON: number of bonds NOT involving H atoms in solute" + self.line_seperator + ) result += self.field_seperator + str(self.NBON) + self.line_seperator result += super().block_to_string() result += "END\n" return result + class BONDH(_topology_table_block): NBONH: int = 1 table_header: Iterable[str] = ["IBH", "JBH", "ICBH"] - table_line_type = top_bond_type #reused data type for simplicity + table_line_type = top_bond_type # reused data type for simplicity - def __init__(self, content: Union[Iterable[top_bond_type], str], - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None, - NBONH = None): + def __init__( + self, + content: Union[Iterable[top_bond_type], str], + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + NBONH=None, + ): """ GROMOS BONDH block @@ -2099,27 +2522,35 @@ def __init__(self, content: Union[Iterable[top_bond_type], str], NBONH : int, optional Number of bonds with H """ - kwargs = {"NBONH" : NBONH} + kwargs = {"NBONH": NBONH} super().__init__(content=content, FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, **kwargs) + def read_content_from_str(self, content: str): super().read_content_from_str(content) + def block_to_string(self) -> str: result = self.name + "\n" - result += "#" + self.field_seperator + "NBONH: number of bonds involving H atoms in solute" + self.line_seperator + result += ( + "#" + self.field_seperator + "NBONH: number of bonds involving H atoms in solute" + self.line_seperator + ) result += self.field_seperator + str(self.NBONH) + self.line_seperator result += super().block_to_string() result += "END\n" return result + class BONDANGLEBENDTYPE(_topology_table_block): NBTY: int table_header: Iterable[str] = ["CT", "CHT", "T0"] table_line_type = bondanglebendtype_type - def __init__(self, content: Union[Iterable[bondanglebendtype_type], str], - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None, - NBTY = None): + def __init__( + self, + content: Union[Iterable[bondanglebendtype_type], str], + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + NBTY=None, + ): """ GROMOS BONDSTRETCHTYPE block @@ -2131,10 +2562,12 @@ def __init__(self, content: Union[Iterable[bondanglebendtype_type], str], NBTY : int, optional Number of bondstretchtypes """ - kwargs = {"NBTY" : NBTY} + kwargs = {"NBTY": NBTY} super().__init__(content=content, FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, **kwargs) + def read_content_from_str(self, content: str): super().read_content_from_str(content) + def block_to_string(self) -> str: result = self.name + "\n" result += "#" + self.field_seperator + "NBTY: number of angle types" + self.line_seperator @@ -2143,15 +2576,19 @@ def block_to_string(self) -> str: result += "END\n" return result + class BONDANGLE(_topology_table_block): NTHE: int table_header: Iterable[str] = ["IT", "JT", "KT", "ICT"] table_line_type = bondangle_type - def __init__(self, content: Union[Iterable[bondangle_type], str], - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None, - NTHE = None): + def __init__( + self, + content: Union[Iterable[bondangle_type], str], + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + NTHE=None, + ): """ GROMOS BONDSTRETCHTYPE block @@ -2163,10 +2600,12 @@ def __init__(self, content: Union[Iterable[bondangle_type], str], NTHE : int, optional Number of bondangles """ - kwargs = {"NTHE" : NTHE} + kwargs = {"NTHE": NTHE} super().__init__(content=content, FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, **kwargs) + def read_content_from_str(self, content: str): super().read_content_from_str(content) + def block_to_string(self) -> str: result = self.name + "\n" result += "#" + self.field_seperator + "NTHE: number of angles" + self.line_seperator @@ -2175,15 +2614,19 @@ def block_to_string(self) -> str: result += "END\n" return result + class BONDANGLEH(_topology_table_block): NTHEH: int table_header: Iterable[str] = ["ITH", "JTH", "KTH", "ICTH"] table_line_type = bondangle_type - def __init__(self, content: Union[Iterable[bondangle_type], str], - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None, - NTHEH = None): + def __init__( + self, + content: Union[Iterable[bondangle_type], str], + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + NTHEH=None, + ): """ GROMOS BONDANGLEH block @@ -2195,10 +2638,12 @@ def __init__(self, content: Union[Iterable[bondangle_type], str], NTHEH : int, optional Number of bondangles """ - kwargs = {"NTHEH" : NTHEH} + kwargs = {"NTHEH": NTHEH} super().__init__(content=content, FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, **kwargs) + def read_content_from_str(self, content: str): super().read_content_from_str(content) + def block_to_string(self) -> str: result = self.name + "\n" result += "#" + self.field_seperator + "NTHEH: number of bondangles involving a H" + self.line_seperator @@ -2210,13 +2655,16 @@ def block_to_string(self) -> str: class IMPDIHEDRALTYPE(_topology_table_block): NQTY: int - table_header: Iterable[str] = ["CQ","Q0"] + table_header: Iterable[str] = ["CQ", "Q0"] table_line_type = impdihedraltype_type - def __init__(self, content: Union[Iterable[impdihedraltype_type], str], - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None, - NQTY = None): + def __init__( + self, + content: Union[Iterable[impdihedraltype_type], str], + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + NQTY=None, + ): """ GROMOS IMPDIHEDRALTYPE block @@ -2228,7 +2676,7 @@ def __init__(self, content: Union[Iterable[impdihedraltype_type], str], NQTY : int, optional Number of impdihedraltype """ - kwargs = {"NQTY" : NQTY} + kwargs = {"NQTY": NQTY} super().__init__(content=content, FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, **kwargs) def read_content_from_str(self, content: str): @@ -2242,15 +2690,19 @@ def block_to_string(self) -> str: result += "END\n" return result + class IMPDIHEDRALH(_topology_table_block): NQHIH: int - table_header: Iterable[str] = ["IQH","JQH","KQH","LQH","ICQH"] + table_header: Iterable[str] = ["IQH", "JQH", "KQH", "LQH", "ICQH"] table_line_type = impdihedralh_type - def __init__(self, content: Union[Iterable[impdihedralh_type], str], - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None, - NQHIH = None): + def __init__( + self, + content: Union[Iterable[impdihedralh_type], str], + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + NQHIH=None, + ): """ GROMOS IMPDIHEDRALH block @@ -2262,13 +2714,17 @@ def __init__(self, content: Union[Iterable[impdihedralh_type], str], NQHIH : int, optional Number of impdihedralH """ - kwargs = {"NQHIH" : NQHIH} + kwargs = {"NQHIH": NQHIH} super().__init__(content=content, FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, **kwargs) + def read_content_from_str(self, content: str): super().read_content_from_str(content) + def block_to_string(self) -> str: result = self.name + "\n" - result += "#" + self.field_seperator + "NQHIH: number of improper dihedrals involving H atoms" + self.line_seperator + result += ( + "#" + self.field_seperator + "NQHIH: number of improper dihedrals involving H atoms" + self.line_seperator + ) result += self.field_seperator + str(self.NQHIH) + self.line_seperator result += super().block_to_string() result += "END\n" @@ -2277,13 +2733,16 @@ def block_to_string(self) -> str: class IMPDIHEDRAL(_topology_table_block): NQHI: int - table_header: Iterable[str] = ["IQ","JQ","KQ","LQ","ICQ"] + table_header: Iterable[str] = ["IQ", "JQ", "KQ", "LQ", "ICQ"] table_line_type = impdihedral_type - def __init__(self, content: Union[Iterable[impdihedral_type], str], - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None, - NQHI = None): + def __init__( + self, + content: Union[Iterable[impdihedral_type], str], + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + NQHI=None, + ): """ GROMOS IMPDIHEDRAL block @@ -2295,13 +2754,20 @@ def __init__(self, content: Union[Iterable[impdihedral_type], str], NQHI : int, optional Number of impdihedral """ - kwargs = {"NQHI" : NQHI} + kwargs = {"NQHI": NQHI} super().__init__(content=content, FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, **kwargs) + def read_content_from_str(self, content: str): super().read_content_from_str(content) + def block_to_string(self) -> str: result = self.name + "\n" - result += "#" + self.field_seperator + "NQHI: number of improper dihedrals NOT involving H atoms" + self.line_seperator + result += ( + "#" + + self.field_seperator + + "NQHI: number of improper dihedrals NOT involving H atoms" + + self.line_seperator + ) result += self.field_seperator + str(self.NQHI) + self.line_seperator result += super().block_to_string() result += "END\n" @@ -2311,21 +2777,25 @@ def block_to_string(self) -> str: result = self.name + "\n" result += "#" + self.field_seperator + "# NQHI: number of improper dihedrals" + self.line_seperator result += self.field_seperator + str(self.NQHI) + self.line_seperator - result += "#"+self.field_seperator+self.field_seperator.join(self.table_header)+self.line_seperator + result += "#" + self.field_seperator + self.field_seperator.join(self.table_header) + self.line_seperator for x in self.content: result += x.to_string() result += "END\n" return result + class TORSDIHEDRALTYPE(_topology_table_block): NPTY: int table_header: Iterable[str] = ["CP", "PD", "NP"] table_line_type = torsdihedraltype_type - def __init__(self, content: Union[Iterable[torsdihedraltype_type], str], - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None, - NPTY = None): + def __init__( + self, + content: Union[Iterable[torsdihedraltype_type], str], + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + NPTY=None, + ): """ GROMOS IMPDIHEDRAL block @@ -2337,10 +2807,12 @@ def __init__(self, content: Union[Iterable[torsdihedraltype_type], str], NQTY : int, optional Number of torsion dihedrals """ - kwargs = {"NPTY" : NPTY} + kwargs = {"NPTY": NPTY} super().__init__(content=content, FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, **kwargs) + def read_content_from_str(self, content: str): super().read_content_from_str(content) + def block_to_string(self) -> str: result = self.name + "\n" result += "#" + self.field_seperator + "NPTY: number of torsion dihedrals" + self.line_seperator @@ -2349,15 +2821,19 @@ def block_to_string(self) -> str: result += "END\n" return result + class DIHEDRALH(_topology_table_block): NPHIH: int - table_header: Iterable[str] = ["IPH","JPH","KPH","LPH","ICPH"] + table_header: Iterable[str] = ["IPH", "JPH", "KPH", "LPH", "ICPH"] table_line_type = dihedralh_type - def __init__(self, content: Union[Iterable[dihedralh_type], str], - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None, - NPHIH = None): + def __init__( + self, + content: Union[Iterable[dihedralh_type], str], + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + NPHIH=None, + ): """ GROMOS DIHEDRAL block @@ -2369,13 +2845,17 @@ def __init__(self, content: Union[Iterable[dihedralh_type], str], NPHIH : int, optional Number of dihedralH """ - kwargs = {"NPHIH" : NPHIH} + kwargs = {"NPHIH": NPHIH} super().__init__(content=content, FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, **kwargs) + def read_content_from_str(self, content: str): super().read_content_from_str(content) + def block_to_string(self) -> str: result = self.name + "\n" - result += "#" + self.field_seperator + "NPHIH: number of torsion dihedrals involving H atoms" + self.line_seperator + result += ( + "#" + self.field_seperator + "NPHIH: number of torsion dihedrals involving H atoms" + self.line_seperator + ) result += self.field_seperator + str(self.NPHIH) + self.line_seperator result += super().block_to_string() result += "END\n" @@ -2384,13 +2864,16 @@ def block_to_string(self) -> str: class DIHEDRAL(_topology_table_block): NPHI: int - table_header: Iterable[str] = ["IP","JP","KP","LP","ICP"] + table_header: Iterable[str] = ["IP", "JP", "KP", "LP", "ICP"] table_line_type = top_dihedral_type - def __init__(self, content: Union[Iterable[top_dihedral_type], str], - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None, - NPHI = None): + def __init__( + self, + content: Union[Iterable[top_dihedral_type], str], + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + NPHI=None, + ): """ GROMOS DIHEDRAL block @@ -2402,10 +2885,12 @@ def __init__(self, content: Union[Iterable[top_dihedral_type], str], NPHI : int, optional Number of tors dihedral """ - kwargs = {"NPHI" : NPHI} + kwargs = {"NPHI": NPHI} super().__init__(content=content, FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, **kwargs) + def read_content_from_str(self, content: str): super().read_content_from_str(content) + def block_to_string(self) -> str: result = self.name + "\n" result += "#" + self.field_seperator + "NPHI: number of dihedrals NOT involving H atoms" + self.line_seperator @@ -2420,10 +2905,13 @@ class CROSSDIHEDRALH(_topology_table_block): table_header: Iterable[str] = ["APH", "BPH", "CPH", "DPH", "EPH", "FPH", "GPH", "HPH", "ICCH"] table_line_type = crossgihedralh_type - def __init__(self, content: Union[Iterable[crossgihedralh_type], str], - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None, - NPHIH = None): + def __init__( + self, + content: Union[Iterable[crossgihedralh_type], str], + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + NPHIH=None, + ): """[summary] Parameters @@ -2437,10 +2925,12 @@ def __init__(self, content: Union[Iterable[crossgihedralh_type], str], NPHIH : [type], optional number of cross dihedrals involving H atoms in solute, by default None """ - kwargs = {"NPHIH" : NPHIH} + kwargs = {"NPHIH": NPHIH} super().__init__(content=content, FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, **kwargs) + def read_content_from_str(self, content: str): super().read_content_from_str(content) + def block_to_string(self) -> str: result = self.name + "\n" result += "#" + self.field_seperator + "NPHIH: number of dihedrals involving H atoms" + self.line_seperator @@ -2455,10 +2945,13 @@ class CROSSDIHEDRAL(_topology_table_block): table_header: Iterable[str] = ["AP", "BP", "CP", "DP", "EP", "FP", "GP", "HP", "ICC"] table_line_type = crossgihedralh_type - def __init__(self, content: Union[Iterable[crossgihedral_type], str], - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None, - NPHI = None): + def __init__( + self, + content: Union[Iterable[crossgihedral_type], str], + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + NPHI=None, + ): """[summary] Parameters @@ -2472,13 +2965,17 @@ def __init__(self, content: Union[Iterable[crossgihedral_type], str], NPHI : [type], optional number of cross dihedrals NOT involving H atoms in solute, by default None """ - kwargs = {"NPHI" : NPHI} + kwargs = {"NPHI": NPHI} super().__init__(content=content, FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, **kwargs) + def read_content_from_str(self, content: str): super().read_content_from_str(content) + def block_to_string(self) -> str: result = self.name + "\n" - result += "#" + self.field_seperator + "NPHI: number of cross dihedrals NOT involving H atoms" + self.line_seperator + result += ( + "#" + self.field_seperator + "NPHI: number of cross dihedrals NOT involving H atoms" + self.line_seperator + ) result += self.field_seperator + str(self.NPHI) + self.line_seperator result += super().block_to_string() result += "END\n" @@ -2490,10 +2987,13 @@ class LJPARAMETERS(_topology_table_block): table_header: Iterable[str] = ["IAC", "JAC", "C12", "C6", "CS12", "CS6"] table_line_type = ljparameters_type - def __init__(self, content: Union[Iterable[ljparameters_type], str], - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None, - NRATT2 = None): + def __init__( + self, + content: Union[Iterable[ljparameters_type], str], + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + NRATT2=None, + ): """ GROMOS LJPARAMETERS block @@ -2505,13 +3005,20 @@ def __init__(self, content: Union[Iterable[ljparameters_type], str], NRATT2 : int, optional Number of LJPARAMETERS """ - kwargs = {"NRATT2" : NRATT2} + kwargs = {"NRATT2": NRATT2} super().__init__(content=content, FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, **kwargs) + def read_content_from_str(self, content: str): super().read_content_from_str(content) + def block_to_string(self) -> str: result = self.name + "\n" - result += "#" + self.field_seperator + "NRATT2: number of LJ interaction types = NRATT*(NRATT+1)/2" + self.line_seperator + result += ( + "#" + + self.field_seperator + + "NRATT2: number of LJ interaction types = NRATT*(NRATT+1)/2" + + self.line_seperator + ) result += self.field_seperator + str(self.NRATT2) + self.line_seperator result += super().block_to_string() result += "END\n" @@ -2519,33 +3026,47 @@ def block_to_string(self) -> str: class SOLUTEMOLECULES(_topology_block): - def __init__(self, content:(str or dict or None or __class__), - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None): + def __init__( + self, + content: (str or dict or None or __class__), + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + ): super().__init__(FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, content=content) + class TEMPERATUREGROUPS(_topology_block): - def __init__(self, content:(str or dict or None or __class__), - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None): + def __init__( + self, + content: (str or dict or None or __class__), + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + ): super().__init__(FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, content=content) + class PRESSUREGROUPS(_topology_block): - def __init__(self, content:(str or dict or None or __class__), - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None): + def __init__( + self, + content: (str or dict or None or __class__), + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + ): super().__init__(FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, content=content) class LJEXCEPTIONS(_topology_table_block): NEX: int - table_header: Iterable[str] = ["AT1","AT2", "C12", "C6"] + table_header: Iterable[str] = ["AT1", "AT2", "C12", "C6"] table_line_type = ljexception_type - def __init__(self, content: Union[Iterable[ljexception_type], str], - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None, - NEX = None): + def __init__( + self, + content: Union[Iterable[ljexception_type], str], + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + NEX=None, + ): """ GROMOS LJEXCEPTIONS block @@ -2557,10 +3078,12 @@ def __init__(self, content: Union[Iterable[ljexception_type], str], NEX : int, optional Number of LJEXCEPTIONS """ - kwargs = {"NEX" : NEX} + kwargs = {"NEX": NEX} super().__init__(content=content, FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, **kwargs) + def read_content_from_str(self, content: str): super().read_content_from_str(content) + def block_to_string(self) -> str: result = self.name + "\n" result += "# This block defines special LJ-interactions based on atom numbers \n# This overrules the normal LJ-parameters (including 1-4 interactions)\n" @@ -2576,10 +3099,13 @@ class SOLVENTATOM(_topology_table_block): table_header: Iterable[str] = ["I", "ANMS", "IACS", "MASS", "CGS"] table_line_type = solventatom_type - def __init__(self, content: Union[Iterable[solventatom_type], str], - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None, - NRAM = None): + def __init__( + self, + content: Union[Iterable[solventatom_type], str], + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + NRAM=None, + ): """ GROMOS solventatom block @@ -2591,10 +3117,12 @@ def __init__(self, content: Union[Iterable[solventatom_type], str], NRAM : int, optional Number of solventatom """ - kwargs = {"NRAM" : NRAM} + kwargs = {"NRAM": NRAM} super().__init__(content=content, FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, **kwargs) + def read_content_from_str(self, content: str): super().read_content_from_str(content) + def block_to_string(self) -> str: result = self.name + "\n" result += "#" + self.field_seperator + "NRAM: number of atoms per solvent molecule" + self.line_seperator @@ -2609,10 +3137,13 @@ class SOLVENTCONSTR(_topology_table_block): table_header: Iterable[str] = ["ICONS", "JCONS", "CONS"] table_line_type = solventconstr_type - def __init__(self, content: Union[Iterable[solventconstr_type], str], - FORCEFIELD: FORCEFIELD = None, - MAKETOPVERSION: MAKETOPVERSION = None, - NCONS = None): + def __init__( + self, + content: Union[Iterable[solventconstr_type], str], + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + NCONS=None, + ): """ GROMOS SOLVENTCONSTR block @@ -2624,10 +3155,12 @@ def __init__(self, content: Union[Iterable[solventconstr_type], str], NCONS : int, optional Number of SOLVENTCONSTR """ - kwargs = {"NCONS" : NCONS} + kwargs = {"NCONS": NCONS} super().__init__(content=content, FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, **kwargs) + def read_content_from_str(self, content: str): super().read_content_from_str(content) + def block_to_string(self) -> str: result = self.name + "\n" result += "#" + self.field_seperator + "NCONS: number of constraints" + self.line_seperator @@ -2636,13 +3169,20 @@ def block_to_string(self) -> str: result += "END\n" return result + class CONSTRAINT(_topology_table_block): - NCON:int + NCON: int table_header: Iterable[str] = ["IC", "JC", "ICC"] table_line_type = constraint_type - def __init__(self, content: str or dict or None, FORCEFIELD: FORCEFIELD = None, MAKETOPVERSION: MAKETOPVERSION = None, NCON = None): - kwargs = {"NCON" : NCON} + def __init__( + self, + content: str or dict or None, + FORCEFIELD: FORCEFIELD = None, + MAKETOPVERSION: MAKETOPVERSION = None, + NCON=None, + ): + kwargs = {"NCON": NCON} super().__init__(content=content, FORCEFIELD=FORCEFIELD, MAKETOPVERSION=MAKETOPVERSION, **kwargs) def read_content_from_str(self, content: str): @@ -2656,12 +3196,22 @@ def block_to_string(self) -> str: result += "END\n" return result + pertubation_lam_state = namedtuple("pertubationLamState", ["IAC", "MASS", "CHARGE"]) + class atom_lam_pertubation_state(_generic_field): state_format_pattern = " {:>5} {:>5} {:>10.5f}" - def __init__(self, NR:int, RES:int, NAME:str, STATES:Dict[int, pertubation_lam_state], ALPHLJ:float=1.0, ALPHCRF:float=1.0): + def __init__( + self, + NR: int, + RES: int, + NAME: str, + STATES: Dict[int, pertubation_lam_state], + ALPHLJ: float = 1.0, + ALPHCRF: float = 1.0, + ): self.NR = int(NR) self.RES = int(RES) self.NAME = NAME @@ -2670,30 +3220,46 @@ def __init__(self, NR:int, RES:int, NAME:str, STATES:Dict[int, pertubation_lam_s self.ALPHCRF = float(ALPHCRF) def to_string(self): - state_str = "".join([self.state_format_pattern.format(int(self.STATES[x].IAC),float(self.STATES[x].MASS), float(self.STATES[x].CHARGE)) for x in sorted(self.STATES)]) - format_str = "{:>5} {:>5} {:>5}"+state_str+" {:10.5f} {:10.5f}\n" - return format_str.format(self.NR, self.RES, self.NAME, self.ALPHLJ, self.ALPHCRF) + state_str = "".join( + [ + self.state_format_pattern.format( + int(self.STATES[x].IAC), float(self.STATES[x].MASS), float(self.STATES[x].CHARGE) + ) + for x in sorted(self.STATES) + ] + ) + format_str = "{:>5} {:>5} {:>5}" + state_str + " {:10.5f} {:10.5f}\n" + return format_str.format(self.NR, self.RES, self.NAME, self.ALPHLJ, self.ALPHCRF) -class PERTATOMPARAM(_generic_gromos_block): - def __init__(self, STATEATOMS:List[atom_lam_pertubation_state]=None, - STATEATOMHEADER: Tuple[str]= None, - NJLA: int=None, STATEIDENTIFIERS=None, - dummy_IAC = 22, dummy_CHARGE=0.0, content:List[str]=None): +class PERTATOMPARAM(_generic_gromos_block): + def __init__( + self, + STATEATOMS: List[atom_lam_pertubation_state] = None, + STATEATOMHEADER: Tuple[str] = None, + NJLA: int = None, + STATEIDENTIFIERS=None, + dummy_IAC=22, + dummy_CHARGE=0.0, + content: List[str] = None, + ): self.NPTB = 2 self.dummy_IAC = dummy_IAC self.dummy_CHARGE = dummy_CHARGE - if(content is None): - if(STATEATOMHEADER is None): - self.STATEATOMHEADER = ["NR", "RES", "NAME",] + if content is None: + if STATEATOMHEADER is None: + self.STATEATOMHEADER = [ + "NR", + "RES", + "NAME", + ] self.STATEATOMHEADER += ["ALPHLJ", "ALPHCRF"] else: self.STATEATOMHEADER = STATEATOMHEADER - - if(STATEATOMS is None): + if STATEATOMS is None: self.STATEATOMS = [] else: self.STATEATOMS = [] @@ -2705,10 +3271,17 @@ def __init__(self, STATEATOMS:List[atom_lam_pertubation_state]=None, super().__init__(used=True, name=__class__.__name__, content=content) # You can check yourself :) - if(not NJLA is None and not len(STATEATOMS)==NJLA): - raise ValueError("NJLA must be equal to the length of STATEATOMS! NJLA="+str(NJLA)+"\t stateatoms"+str(len(STATEATOMS))+"\n\n"+str(self)) - - def read_content_from_str(self, content:List[str]): + if not NJLA is None and not len(STATEATOMS) == NJLA: + raise ValueError( + "NJLA must be equal to the length of STATEATOMS! NJLA=" + + str(NJLA) + + "\t stateatoms" + + str(len(STATEATOMS)) + + "\n\n" + + str(self) + ) + + def read_content_from_str(self, content: List[str]): field = 0 NJLA = None STATEIDENTIFIERS = None @@ -2717,33 +3290,48 @@ def read_content_from_str(self, content:List[str]): first = True stdid = False for line in content: - if ("#" in line): + if "#" in line: comment = line - if("state_identifiers" in line): - stdid=True - elif(stdid): + if "state_identifiers" in line: + stdid = True + elif stdid: STATEIDENTIFIERS = line.replace("#", "").split() - stdid=False + stdid = False continue else: - if (field > 0): - if(first): - STATEATOMHEADER = ["NR", "RES", "NAME",] - [STATEATOMHEADER.extend(["IAC" + str(x), "MASS" + str(x), "CHARGE" + str(x)]) for x in range(1, 3)] + if field > 0: + if first: + STATEATOMHEADER = [ + "NR", + "RES", + "NAME", + ] + [ + STATEATOMHEADER.extend(["IAC" + str(x), "MASS" + str(x), "CHARGE" + str(x)]) + for x in range(1, 3) + ] STATEATOMHEADER += ["ALPHLJ", "ALPHCRF"] first = False state_line = {key: value for key, value in zip(STATEATOMHEADER, line.split())} - final_state_line = {key: state_line[key] for key in state_line if - (not "IAC" in key and not "CHARGE" in key and not "MASS" in key)} - states = {x: pertubation_lam_state(IAC=int(round(float(state_line["IAC" + str(x)]))), - MASS=float(state_line["MASS" + str(x)]), - CHARGE=float(state_line["CHARGE" + str(x)])) for x in range(1, 3)} - - final_state_line.update({"STATES":states}) + final_state_line = { + key: state_line[key] + for key in state_line + if (not "IAC" in key and not "CHARGE" in key and not "MASS" in key) + } + states = { + x: pertubation_lam_state( + IAC=int(round(float(state_line["IAC" + str(x)]))), + MASS=float(state_line["MASS" + str(x)]), + CHARGE=float(state_line["CHARGE" + str(x)]), + ) + for x in range(1, 3) + } + + final_state_line.update({"STATES": states}) STATEATOMS.append(atom_lam_pertubation_state(**final_state_line)) - elif (field == 0): + elif field == 0: NJLA = int(line.strip()) field += 1 @@ -2753,20 +3341,26 @@ def read_content_from_str(self, content:List[str]): self.STATEATOMS = STATEATOMS @property - def nStates(self)->int: + def nStates(self) -> int: return self.NPTB @property - def nTotalStateAtoms(self)->int: + def nTotalStateAtoms(self) -> int: return self.NJLA @property - def states(self)->dict: - return {self.STATEIDENTIFIERS[state-1]: {atom.NR: atom.STATES[state] for atom in sorted(self.STATEATOMS, key=lambda x: x.NR)} for state in range(1, self.NPTB+1)} + def states(self) -> dict: + return { + self.STATEIDENTIFIERS[state - 1]: { + atom.NR: atom.STATES[state] for atom in sorted(self.STATEATOMS, key=lambda x: x.NR) + } + for state in range(1, self.NPTB + 1) + } """ ADD FUNCTIONS """ + def add_state_atoms(self, state_atoms: List[atom_lam_pertubation_state]): """ This function can add states and atoms, but also overwrite state values of existing atoms. @@ -2777,74 +3371,75 @@ def add_state_atoms(self, state_atoms: List[atom_lam_pertubation_state]): state_atoms: List[atom_eds_pertubation_state] """ - #some preperations: - pre_dummy_state = lambda atomMass: pertubation_lam_state(IAC=self.dummy_IAC, MASS=atomMass,CHARGE=self.dummy_CHARGE) + # some preperations: + pre_dummy_state = lambda atomMass: pertubation_lam_state( + IAC=self.dummy_IAC, MASS=atomMass, CHARGE=self.dummy_CHARGE + ) insert_id = self.STATEATOMHEADER.index("ALPHLJ") - #find all new states + # find all new states keys = np.array([list(natom.STATES.keys()) for natom in state_atoms], ndmin=1) unique_stateIDs = np.unique(np.concatenate(keys)) ## Todo: not urgent; state number adaptation ( present states 1,2,3,4 new state 8 - id should be 5 not 8) - unique_states = list(map(str, [ "state"+str(x) if isinstance(x, Number) else x for x in unique_stateIDs])) + unique_states = list(map(str, ["state" + str(x) if isinstance(x, Number) else x for x in unique_stateIDs])) - #insert new state IDs + # insert new state IDs off = 0 for unique_state in unique_stateIDs: - self.STATEATOMHEADER.insert(insert_id+off, "IAC"+str(unique_state)) - self.STATEATOMHEADER.insert(insert_id+off+1, "mass"+str(unique_state)) - self.STATEATOMHEADER.insert(insert_id+off+2, "CHARGE"+str(unique_state)) - off+=3 + self.STATEATOMHEADER.insert(insert_id + off, "IAC" + str(unique_state)) + self.STATEATOMHEADER.insert(insert_id + off + 1, "mass" + str(unique_state)) + self.STATEATOMHEADER.insert(insert_id + off + 2, "CHARGE" + str(unique_state)) + off += 3 - #add new state names - if(hasattr(self, "STATEIDENTIFIERS")): + # add new state names + if hasattr(self, "STATEIDENTIFIERS"): self.STATEIDENTIFIERS.extend(unique_states) self.NPTB += len(unique_states) else: self.STATEIDENTIFIERS = unique_states self.NPTB = len(unique_states) - #increase the number of new states - + # increase the number of new states - #1. Update already present atoms: + # 1. Update already present atoms: atomIDs = [atom.NR for atom in state_atoms] for atom in self.STATEATOMS: atom.STATES.update({key: val for key, val in atom.STATES.items()}) - possible_masses = [val.MASS for key, val in atom.STATES.items() if(val.MASS >0)] + possible_masses = [val.MASS for key, val in atom.STATES.items() if (val.MASS > 0)] dummy_state = pre_dummy_state(atomMass=possible_masses[0]) - if(atom.NR in atomIDs): + if atom.NR in atomIDs: new_atom = state_atoms[atomIDs.index(atom.NR)] atom.NAME = new_atom.NAME atom.STATES.update({key: val for key, val in new_atom.STATES.items()}) - possible_masses = [val.MASS for key, val in new_atom.STATES.items() if(val.MASS >0)] - #add missing dummies - #print(unique_stateIDs) + possible_masses = [val.MASS for key, val in new_atom.STATES.items() if (val.MASS > 0)] + # add missing dummies + # print(unique_stateIDs) atom.STATES.update({key: dummy_state for key in unique_stateIDs if not key in atom.STATES}) - #remove present atom + # remove present atom del atomIDs[atomIDs.index(atom.NR)] else: - #add missing dummies + # add missing dummies atom.STATES.update({key: dummy_state for key in unique_stateIDs if not key in atom.STATES}) - - #2. add new atoms + # 2. add new atoms new_atoms = [atom for atom in state_atoms if (atom.NR in atomIDs)] for atom in new_atoms: atom.STATES.update({key: val for key, val in atom.STATES.items()}) - possible_masses = [val.MASS for key, val in atom.STATES.items() if(val.MASS >0)] + possible_masses = [val.MASS for key, val in atom.STATES.items() if (val.MASS > 0)] dummy_state = pre_dummy_state(atomMass=possible_masses[0]) - atom.STATES.update({key:dummy_state for key in range(1, self.NPTB+1) if (key not in atom.STATES)}) + atom.STATES.update({key: dummy_state for key in range(1, self.NPTB + 1) if (key not in atom.STATES)}) self.STATEATOMS.append(atom) - self.NJLA +=1 + self.NJLA += 1 """ DELETING FUNCTIONS """ - def delete_state(self, stateIDs:(int, List[int])=None, stateNames:(str, List[str])=None): + + def delete_state(self, stateIDs: (int, List[int]) = None, stateNames: (str, List[str]) = None): """ This function deletes an state column. Parameters @@ -2854,40 +3449,45 @@ def delete_state(self, stateIDs:(int, List[int])=None, stateNames:(str, List[str Returns ------- """ - if(not stateIDs is None): - if(isinstance(stateIDs, int)): + if not stateIDs is None: + if isinstance(stateIDs, int): stateIDs = [stateIDs] for state in stateIDs: for atom in self.STATEATOMS: - if(state in atom.STATES): + if state in atom.STATES: del atom.STATES[state] del self.STATEIDENTIFIERS[state - 1] - self.STATEATOMHEADER = [x for x in self.STATEATOMHEADER if - (not x == "IAC" + str(state) and not "CHARGE" + str(state) == x)] + self.STATEATOMHEADER = [ + x for x in self.STATEATOMHEADER if (not x == "IAC" + str(state) and not "CHARGE" + str(state) == x) + ] - self.NPTB-=len(set(stateIDs)) + self.NPTB -= len(set(stateIDs)) - elif(not stateNames is None): - if(isinstance(stateNames, str)): + elif not stateNames is None: + if isinstance(stateNames, str): stateNames = [stateNames] for stateN in stateNames: - #print(stateN) - stateID = self.STATEIDENTIFIERS.index(stateN)+1 + # print(stateN) + stateID = self.STATEIDENTIFIERS.index(stateN) + 1 for atom in self.STATEATOMS: - if(stateID in atom.STATES): - del atom.STATES[stateID] - - del self.STATEIDENTIFIERS[stateID-1] - self.STATEATOMHEADER = [x for x in self.STATEATOMHEADER if( not x == "IAC"+str(stateID) and not "CHARGE"+str(stateID) == x)] + if stateID in atom.STATES: + del atom.STATES[stateID] + + del self.STATEIDENTIFIERS[stateID - 1] + self.STATEATOMHEADER = [ + x + for x in self.STATEATOMHEADER + if (not x == "IAC" + str(stateID) and not "CHARGE" + str(stateID) == x) + ] self.NPTB -= len(set(stateNames)) - elif(not stateNames is None and not stateIDs is None): + elif not stateNames is None and not stateIDs is None: raise Exception("Please give either stateNames or stateIDs") - def delete_atom(self, atomNR:(int, List[int])): + def delete_atom(self, atomNR: (int, List[int])): """ This function removes atom lines from the ptp file. Parameters @@ -2895,13 +3495,13 @@ def delete_atom(self, atomNR:(int, List[int])): atomNR: int atom to be removed. """ - if(isinstance(atomNR, int)): + if isinstance(atomNR, int): atomNR = [atomNR] ind_offset = 0 new_STATEATOMS = [] for ind, atom in enumerate(self.STATEATOMS): - if (atom.NR in atomNR): + if atom.NR in atomNR: continue else: new_STATEATOMS.append(atom) @@ -2909,32 +3509,48 @@ def delete_atom(self, atomNR:(int, List[int])): self.STATEATOMS = new_STATEATOMS self.NJLA -= len(atomNR) - """ STR FUNCTIONS """ + def _state_STATEATOMHEADER_str(self): - state_format_pattern = "{:>5} {:>5} {:>5}"+"".join([" {:>5}{:>5}{:>10}"for x in range(self.NPTB)])+" {:10} {:10}" + state_format_pattern = ( + "{:>5} {:>5} {:>5}" + "".join([" {:>5}{:>5}{:>10}" for x in range(self.NPTB)]) + " {:10} {:10}" + ) return state_format_pattern.format(*self.STATEATOMHEADER) def block_to_string(self) -> str: result = self.name + self.line_seperator - result += "# NJLA " + self.field_seperator + "NPTB = " + self.field_seperator + str(self.NPTB) + self.field_seperator+ self.line_seperator - result += self.field_seperator + str(self.NJLA)+self.line_seperator + result += ( + "# NJLA " + + self.field_seperator + + "NPTB = " + + self.field_seperator + + str(self.NPTB) + + self.field_seperator + + self.line_seperator + ) + result += self.field_seperator + str(self.NJLA) + self.line_seperator result += "# state_identifiers" + self.line_seperator - result += "# "+self.field_seperator + self.field_seperator.join(map(str, self.STATEIDENTIFIERS)) + self.line_seperator + result += ( + "# " + + self.field_seperator + + self.field_seperator.join(map(str, self.STATEIDENTIFIERS)) + + self.line_seperator + ) result += "# " + self._state_STATEATOMHEADER_str() + self.line_seperator result += "".join(map(str, sorted(self.STATEATOMS, key=lambda x: x.NR))) - result += "END"+self.line_seperator + result += "END" + self.line_seperator return result + class SCALEDINTERACTIONS(_generic_gromos_block): def __init__(self, values=None, content=None): """ Not exactly sure what these parameters do """ - if (content is None): + if content is None: super().__init__(used=True, name=__class__.__name__) self.values = values else: @@ -2957,4 +3573,4 @@ def read_content_from_str(self, content): for v in content[1].split(): values.append(v) - self.values = values \ No newline at end of file + self.values = values diff --git a/pygromos/files/coord/__init__.py b/pygromos/files/coord/__init__.py index fd440783..9d7db219 100644 --- a/pygromos/files/coord/__init__.py +++ b/pygromos/files/coord/__init__.py @@ -1 +1 @@ -from pygromos.files.coord.cnf import * \ No newline at end of file +from pygromos.files.coord.cnf import * diff --git a/pygromos/files/coord/cnf.py b/pygromos/files/coord/cnf.py index 30347b97..d2037fd0 100644 --- a/pygromos/files/coord/cnf.py +++ b/pygromos/files/coord/cnf.py @@ -700,13 +700,12 @@ def get_last_atomID(self) -> int: Returns ------- - int + int Returns the last atom of the system. """ return self.POSITION.content[-1].atomID - - def center_of_geometry(self, selectedAtoms:list=None) -> list: + def center_of_geometry(self, selectedAtoms: list = None) -> list: """calculates the center of geometry for asingle molecule or the selected Atoms Returns @@ -1048,8 +1047,7 @@ def createRDKITconf(self, mol: Chem.rdchem.Mol, conversionFactor: float = 0.1): # Defaults set for GENBOX - for liquid sim adjust manually self.__setattr__("GENBOX", blocks.GENBOX(pbc=1, length=[4, 4, 4], angles=[90, 90, 90])) - - def get_pdb(self, rdkit_ready:bool=True, connectivity_top=None)->str: + def get_pdb(self, rdkit_ready: bool = True, connectivity_top=None) -> str: """ translate cnf to pdb. diff --git a/pygromos/files/coord/posres.py b/pygromos/files/coord/posres.py index 3e2f4c65..5b8889fc 100644 --- a/pygromos/files/coord/posres.py +++ b/pygromos/files/coord/posres.py @@ -10,7 +10,6 @@ from pygromos.files.blocks import coord_blocks as blocks - class Position_Restraints(Cnf): """ This class is a representation of the gromos .cnf coordinate files. It @@ -18,8 +17,9 @@ class Position_Restraints(Cnf): is a child of general_gromos_file """ - _future_file:bool - path:str + + _future_file: bool + path: str # general _gromos_file_ending: str = "pos" @@ -31,16 +31,23 @@ class Position_Restraints(Cnf): LATTICESHIFTS: blocks.LATTICESHIFTS = None # private - _block_order: List[str] = ["TITLE", "POSRESSPEC", ] + _block_order: List[str] = [ + "TITLE", + "POSRESSPEC", + ] _required_blocks: List[str] = ["TITLE", "POSRESSPEC"] - _main_block:str = "POSRESSPEC" - - def __init__(self, in_value: (str or dict or None or __class__ or Cnf), - clean_resiNumbers_by_Name=False, - verbose: bool = False, _future_file: bool = False): - if(isinstance(in_value, Cnf)): + _main_block: str = "POSRESSPEC" + + def __init__( + self, + in_value: (str or dict or None or __class__ or Cnf), + clean_resiNumbers_by_Name=False, + verbose: bool = False, + _future_file: bool = False, + ): + if isinstance(in_value, Cnf): for block in self._block_order: - if(hasattr(in_value, block)): + if hasattr(in_value, block): setattr(self, block, getattr(in_value, block)) self.POSRESSPEC = blocks.POSRESSPEC(in_value.POSITION.block_to_string().split("\n")[1:-2]) self.path = None diff --git a/pygromos/files/coord/refpos.py b/pygromos/files/coord/refpos.py index 7d780e4a..04bf0d1d 100644 --- a/pygromos/files/coord/refpos.py +++ b/pygromos/files/coord/refpos.py @@ -10,8 +10,9 @@ class Reference_Position(Cnf): is a child of general_gromos_file """ - _future_file:bool - path:str + + _future_file: bool + path: str # general _gromos_file_ending: str = "rpf" @@ -23,15 +24,16 @@ class Reference_Position(Cnf): LATTICESHIFTS: blocks.LATTICESHIFTS = None GENBOX: blocks.GENBOX # private - _block_order: List[str] = ["TITLE", "REFPOSITION", "LATTICESHIFTS", "GENBOX" ] + _block_order: List[str] = ["TITLE", "REFPOSITION", "LATTICESHIFTS", "GENBOX"] _required_blocks: List[str] = ["TITLE", "REFPOSITION"] - _main_block:str = "REFPOSITION" + _main_block: str = "REFPOSITION" - def __init__(self, in_value: (str or dict or None or __class__ or Cnf), - verbose: bool = False, _future_file: bool = False): - if(isinstance(in_value, Cnf)): + def __init__( + self, in_value: (str or dict or None or __class__ or Cnf), verbose: bool = False, _future_file: bool = False + ): + if isinstance(in_value, Cnf): for block in self._block_order: - if(hasattr(in_value, block)): + if hasattr(in_value, block): setattr(self, block, getattr(in_value, block)) self.REFPOSITION = blocks.REFPOSITION(in_value.POSITION.content) self.path = None diff --git a/pygromos/files/gromos_system/__init__.py b/pygromos/files/gromos_system/__init__.py index c7f68f2f..c5b17d73 100644 --- a/pygromos/files/gromos_system/__init__.py +++ b/pygromos/files/gromos_system/__init__.py @@ -1,6 +1,7 @@ from pygromos.files.gromos_system.gromos_system import Gromos_System import importlib -if(importlib.util.find_spec("openforcefield") != None): + +if importlib.util.find_spec("openforcefield") != None: from pygromos.files.gromos_system.ff.serenityff import serenityff from pygromos.files.gromos_system.ff.openforcefield2gromos import openforcefield2gromos diff --git a/pygromos/files/gromos_system/ff/forcefield_system.py b/pygromos/files/gromos_system/ff/forcefield_system.py index 04ae6386..64a8eb6e 100644 --- a/pygromos/files/gromos_system/ff/forcefield_system.py +++ b/pygromos/files/gromos_system/ff/forcefield_system.py @@ -20,19 +20,19 @@ from pygromos.data.ff import Gromos2016H66 from pygromos.data.ff import Gromos54A7 -if (importlib.util.find_spec("openff") != None): +if importlib.util.find_spec("openff") != None: from openff.toolkit.typing.engines import smirnoff + has_openff = True else: has_openff = False - -class forcefield_system(): - def __init__(self, name:str="2016H66", path:str=None, auto_import:bool = True): +class forcefield_system: + def __init__(self, name: str = "2016H66", path: str = None, auto_import: bool = True): self.name = name self.path = path - self.mol_name=None + self.mol_name = None if auto_import: self.auto_import_ff() @@ -55,20 +55,22 @@ def auto_import_ff(self): self.import_off() self.top = Top(in_value=topology_templates.topology_template_dir + "/blank_template+spc.top") self.develop = False - self.C12_input={} + self.C12_input = {} self.partial_charges = collections.defaultdict(float) def import_off(self): if not has_openff: - raise ImportError("Could not import smirnoff FF as openFF toolkit was missing! " - "Please install the package for this feature!") + raise ImportError( + "Could not import smirnoff FF as openFF toolkit was missing! " + "Please install the package for this feature!" + ) if self.path != None: try: self.off = smirnoff.ForceField(self.path) except: - raise ImportError("Could not import a OpenForceField from path: " +str(self.path)) + raise ImportError("Could not import a OpenForceField from path: " + str(self.path)) else: - filelist = glob.glob(ff.data_ff_SMIRNOFF + '/*.offxml') + filelist = glob.glob(ff.data_ff_SMIRNOFF + "/*.offxml") filelist.sort() filelist.reverse() for f in filelist: @@ -78,4 +80,4 @@ def import_off(self): break except Exception as err: pass - print("Found off: "+str(self.path)) + print("Found off: " + str(self.path)) diff --git a/pygromos/files/gromos_system/ff/openforcefield2gromos.py b/pygromos/files/gromos_system/ff/openforcefield2gromos.py index adb7e16a..6d70a6bb 100644 --- a/pygromos/files/gromos_system/ff/openforcefield2gromos.py +++ b/pygromos/files/gromos_system/ff/openforcefield2gromos.py @@ -7,26 +7,30 @@ Author: Marc Lehner """ -#imports +# imports import importlib from pygromos.files.topology.top import Top from pygromos.files.gromos_system.ff.forcefield_system import forcefield_system -if(importlib.util.find_spec("openff") == None): - raise ImportError("openforcefield2gromos is not enabled without openFF toolkit package! Please install openFF toolkit.") +if importlib.util.find_spec("openff") == None: + raise ImportError( + "openforcefield2gromos is not enabled without openFF toolkit package! Please install openFF toolkit." + ) else: from openff.toolkit.topology import Molecule, Topology - #from openforcefield.typing.engines import smirnoff - #from openforcefield.typing.engines.smirnoff import forcefield + + # from openforcefield.typing.engines import smirnoff + # from openforcefield.typing.engines.smirnoff import forcefield from pygromos.data import topology_templates import os import collections from simtk import unit as u -class openforcefield2gromos(): - def __init__(self, openFFmolecule:Molecule, gromosTop:Top=None, forcefield:forcefield_system=None): + +class openforcefield2gromos: + def __init__(self, openFFmolecule: Molecule, gromosTop: Top = None, forcefield: forcefield_system = None): self.atomic_number_dict = collections.defaultdict(str) # get openmm atom type code / periodic table self.atomic_number_dict[1] = "H" @@ -52,24 +56,23 @@ def __init__(self, openFFmolecule:Molecule, gromosTop:Top=None, forcefield:force self.atomic_number_dict[35] = "Br" self.atomic_number_dict[53] = "I" - if gromosTop != None: - self.gromosTop=gromosTop + self.gromosTop = gromosTop else: self.gromosTop = Top(in_value=topology_templates.blank_topo_template) self.gromosTop._orig_file_path = os.getcwd() - + self.openFFmolecule = openFFmolecule self.openFFTop = Topology.from_molecules(openFFmolecule) - #import the openforcfield forcefield-file + # import the openforcfield forcefield-file if forcefield != None: self.forcefield = forcefield else: self.forcefield = forcefield_system(name="off") self.off = self.forcefield.off - #create list of all forces + # create list of all forces self.molecule_force_list = [] self.molecule_force_list = self.off.label_molecules(self.openFFTop) self.openmm_system = self.off.create_openmm_system(self.openFFTop) @@ -83,18 +86,18 @@ def convertResname(self): self.gromosTop.add_new_resname(self.openFFmolecule.name) else: self.gromosTop.add_new_resname(self.openFFmolecule.hill_formula) - + def convertBonds(self): for molecule in self.molecule_force_list: for key in molecule["Bonds"]: force = molecule["Bonds"][key] - #hQ = topology.atom(force[0]).atomic_number == 1 or topology.atom(force[1]).atomic_number == 1 - hQ = not all([self.openFFTop.atom(x).atomic_number != 1 for x in key]) - atomI = key[0]+1 - atomJ = key[1]+1 - k = force.k.value_in_unit(u.kilojoule / (u.mole * u.nanometer ** 2)) + # hQ = topology.atom(force[0]).atomic_number == 1 or topology.atom(force[1]).atomic_number == 1 + hQ = not all([self.openFFTop.atom(x).atomic_number != 1 for x in key]) + atomI = key[0] + 1 + atomJ = key[1] + 1 + k = force.k.value_in_unit(u.kilojoule / (u.mole * u.nanometer**2)) b0 = force.length.value_in_unit(u.nanometer) - self.gromosTop.add_new_bond(k=k, b0=b0, atomI=atomI, atomJ=atomJ, includesH=False) #hQ + self.gromosTop.add_new_bond(k=k, b0=b0, atomI=atomI, atomJ=atomJ, includesH=False) # hQ if not hasattr(self.gromosTop, "BONDSTRETCHTYPE"): self.gromosTop.add_block(blocktitle="BONDSTRETCHTYPE", content=[]) if not hasattr(self.gromosTop, "BONDH"): @@ -106,14 +109,16 @@ def convertAngles(self): for molecule in self.molecule_force_list: for key in molecule["Angles"]: force = molecule["Angles"][key] - hQ = not all([self.openFFTop.atom(x).atomic_number != 1 for x in key]) - atomI=key[0]+1 - atomJ=key[1]+1 - atomK=key[2]+1 - k = 0 #TODO: proper conversion to quartic - kh = force.k.value_in_unit(u.kilojoule / (u.mole * u.degree ** 2)) + hQ = not all([self.openFFTop.atom(x).atomic_number != 1 for x in key]) + atomI = key[0] + 1 + atomJ = key[1] + 1 + atomK = key[2] + 1 + k = 0 # TODO: proper conversion to quartic + kh = force.k.value_in_unit(u.kilojoule / (u.mole * u.degree**2)) b0 = force.angle.value_in_unit(u.degree) - self.gromosTop.add_new_angle(k=k, kh=kh, b0=b0, atomI=atomI, atomJ=atomJ, atomK=atomK, includesH=False, convertToQuartic=True) #hQ + self.gromosTop.add_new_angle( + k=k, kh=kh, b0=b0, atomI=atomI, atomJ=atomJ, atomK=atomK, includesH=False, convertToQuartic=True + ) # hQ if not hasattr(self.gromosTop, "BONDANGLEBENDTYPE"): self.gromosTop.add_block(blocktitle="BONDANGLEBENDTYPE", content=[]) if not hasattr(self.gromosTop, "BONDANGLEH"): @@ -125,23 +130,25 @@ def convertTosions(self): for molecule in self.molecule_force_list: for key in molecule["ProperTorsions"]: force = molecule["ProperTorsions"][key] - hQ = not all([self.openFFTop.atom(x).atomic_number != 1 for x in key]) - atomI=key[0]+1 - atomJ=key[1]+1 - atomK=key[2]+1 - atomL=key[3]+1 + hQ = not all([self.openFFTop.atom(x).atomic_number != 1 for x in key]) + atomI = key[0] + 1 + atomJ = key[1] + 1 + atomK = key[2] + 1 + atomL = key[3] + 1 k_list = force.k phase_list = force.phase per_list = force.periodicity for t in range(len(k_list)): - CP=k_list[t].value_in_unit(u.kilojoule_per_mole) - PD=phase_list[t].value_in_unit(u.degree) - NP=per_list[t] + CP = k_list[t].value_in_unit(u.kilojoule_per_mole) + PD = phase_list[t].value_in_unit(u.degree) + NP = per_list[t] # convert negativ CP by phase shifting if CP < 0: CP = abs(CP) PD += 180 - self.gromosTop.add_new_torsiondihedral(CP=CP, PD=PD, NP=NP, atomI=atomI, atomJ=atomJ, atomK=atomK, atomL=atomL, includesH=False)#hQ + self.gromosTop.add_new_torsiondihedral( + CP=CP, PD=PD, NP=NP, atomI=atomI, atomJ=atomJ, atomK=atomK, atomL=atomL, includesH=False + ) # hQ if not hasattr(self.gromosTop, "TORSDIHEDRALTYPE"): self.gromosTop.add_block(blocktitle="TORSDIHEDRALTYPE", content=[]) if not hasattr(self.gromosTop, "DIHEDRALH"): @@ -153,19 +160,21 @@ def convertImproper(self): for molecule in self.molecule_force_list: for key in molecule["ImproperTorsions"]: force = molecule["ImproperTorsions"][key] - hQ = not all([self.openFFTop.atom(x).atomic_number != 1 for x in key]) - atomI=key[0]+1 - atomJ=key[1]+1 - atomK=key[2]+1 - atomL=key[3]+1 + hQ = not all([self.openFFTop.atom(x).atomic_number != 1 for x in key]) + atomI = key[0] + 1 + atomJ = key[1] + 1 + atomK = key[2] + 1 + atomL = key[3] + 1 k_list = force.k phase_list = force.phase per_list = force.periodicity for t in range(len(k_list)): - CP=k_list[t].value_in_unit(u.kilojoule/u.mole) - PD=phase_list[t].value_in_unit(u.degree) - NP=per_list[t] - self.gromosTop.add_new_torsiondihedral(CP=CP, PD=PD, NP=NP, atomI=atomI, atomJ=atomJ, atomK=atomK, atomL=atomL, includesH=False) #hQ + CP = k_list[t].value_in_unit(u.kilojoule / u.mole) + PD = phase_list[t].value_in_unit(u.degree) + NP = per_list[t] + self.gromosTop.add_new_torsiondihedral( + CP=CP, PD=PD, NP=NP, atomI=atomI, atomJ=atomJ, atomK=atomK, atomL=atomL, includesH=False + ) # hQ if not hasattr(self.gromosTop, "IMPDIHEDRALTYPE"): self.gromosTop.add_block(blocktitle="IMPDIHEDRALTYPE", content=[]) if not hasattr(self.gromosTop, "IMPDIHEDRALH"): @@ -173,9 +182,8 @@ def convertImproper(self): if not hasattr(self.gromosTop, "IMPDIHEDRAL"): self.gromosTop.add_block(blocktitle="IMPDIHEDRAL", content=[]) - def createVdWexclusionList(self): - bondDict=dict() + bondDict = dict() ex13 = dict() ex14 = dict() # create a list of all bonds @@ -187,10 +195,10 @@ def createVdWexclusionList(self): if not str(key[1]) in bondDict.keys(): bondDict[str(key[1])] = {key[0]} bondDict[str(key[1])].add(key[0]) - #use bond dict to createexclusion lists + # use bond dict to createexclusion lists for lvl1 in bondDict: ex13[lvl1] = bondDict[lvl1].copy() - ex14[lvl1] = bondDict[lvl1].copy() #just init 1-3 values will be removed later + ex14[lvl1] = bondDict[lvl1].copy() # just init 1-3 values will be removed later for lvl2 in bondDict[lvl1]: ex13[lvl1].add(lvl2) for lvl3 in bondDict[str(lvl2)]: @@ -208,13 +216,11 @@ def createVdWexclusionList(self): for key in ex14: for i in range(0, int(key) + 1): ex14[key].discard(i) - + # return self.exclusionList13 = ex13 self.exclusionList14 = ex14 - - def convertVdW(self): self.createVdWexclusionList() moleculeItr = 1 @@ -226,70 +232,95 @@ def convertVdW(self): force = molecule["vdW"][key] ATNM = int(key[0]) + 1 + prev_atom_counter MRES = moleculeItr - # get element sympol: + # get element sympol: atomic_number = self.openFFmolecule.atoms[int(key[0])].atomic_number element_symbol = self.atomic_number_dict[atomic_number] panm_dict[element_symbol] += 1 PANM = element_symbol + str(panm_dict[element_symbol]) IAC = 0 MASS = self.openFFmolecule.atoms[int(key[0])].mass.value_in_unit(u.dalton) - CG = self.openmm_system.getForce(1).getParticleParameters(int(key[0]))[0].value_in_unit(u.elementary_charge) - CGC = 1 if (int(key[0])+1 == tot_len) else 0 + CG = ( + self.openmm_system.getForce(1) + .getParticleParameters(int(key[0]))[0] + .value_in_unit(u.elementary_charge) + ) + CGC = 1 if (int(key[0]) + 1 == tot_len) else 0 if str(key[0]) in self.exclusionList13: openFFexList13 = list(self.exclusionList13[str(key[0])]) - INE = [int(x)+1 for x in openFFexList13] + INE = [int(x) + 1 for x in openFFexList13] else: INE = list() if str(key[0]) in self.exclusionList14: openFFexList14 = list(self.exclusionList14[str(key[0])]) - INE14 = [int(x)+1 for x in openFFexList14] + INE14 = [int(x) + 1 for x in openFFexList14] else: INE14 = list() epsilon = float(force.epsilon.value_in_unit(u.kilojoule_per_mole)) rmin = 2 * force.rmin_half.value_in_unit(u.nanometer) C6 = 2 * epsilon * (rmin**6) C12 = epsilon * (rmin**12) - CS6 = 0.5 * C6 # factor 0.5 for 1-4 interaction. Standart in GROMOS and OpenFF - CS12 = 0.5 * C12 # factor 0.5 for 1-4 interaction. Standart in GROMOS and OpenFF + CS6 = 0.5 * C6 # factor 0.5 for 1-4 interaction. Standart in GROMOS and OpenFF + CS12 = 0.5 * C12 # factor 0.5 for 1-4 interaction. Standart in GROMOS and OpenFF IACname = force.id - self.gromosTop.add_new_atom(ATNM=ATNM, MRES=MRES, PANM=PANM, IAC=IAC, MASS=MASS, CG=CG, CGC=CGC, INE=INE, INE14=INE14, C6=C6, C12=C12, CS6=CS6, CS12=CS12, IACname=IACname) + self.gromosTop.add_new_atom( + ATNM=ATNM, + MRES=MRES, + PANM=PANM, + IAC=IAC, + MASS=MASS, + CG=CG, + CGC=CGC, + INE=INE, + INE14=INE14, + C6=C6, + C12=C12, + CS6=CS6, + CS12=CS12, + IACname=IACname, + ) moleculeItr += 1 prev_atom_counter += tot_len def convert_other_stuff(self): if not hasattr(self.gromosTop, "SOLUTEMOLECULES"): - self.gromosTop.add_block(blocktitle="SOLUTEMOLECULES", content=['1', str(self.openFFmolecule.n_atoms)]) + self.gromosTop.add_block(blocktitle="SOLUTEMOLECULES", content=["1", str(self.openFFmolecule.n_atoms)]) else: - self.gromosTop.SOLUTEMOLECULES.content = [['1'], [str(self.openFFmolecule.n_atoms)]] + self.gromosTop.SOLUTEMOLECULES.content = [["1"], [str(self.openFFmolecule.n_atoms)]] if not hasattr(self.gromosTop, "TEMPERATUREGROUPS"): - self.gromosTop.add_block(blocktitle="TEMPERATUREGROUPS", content=['1', str(self.openFFmolecule.n_atoms)]) + self.gromosTop.add_block(blocktitle="TEMPERATUREGROUPS", content=["1", str(self.openFFmolecule.n_atoms)]) else: - self.gromosTop.TEMPERATUREGROUPS.content = [['1'], [str(self.openFFmolecule.n_atoms)]] + self.gromosTop.TEMPERATUREGROUPS.content = [["1"], [str(self.openFFmolecule.n_atoms)]] if not hasattr(self.gromosTop, "PRESSUREGROUPS"): - self.gromosTop.add_block(blocktitle="PRESSUREGROUPS", content=['1', str(self.openFFmolecule.n_atoms)]) + self.gromosTop.add_block(blocktitle="PRESSUREGROUPS", content=["1", str(self.openFFmolecule.n_atoms)]) else: - self.gromosTop.PRESSUREGROUPS.content = [['1'], [str(self.openFFmolecule.n_atoms)]] + self.gromosTop.PRESSUREGROUPS.content = [["1"], [str(self.openFFmolecule.n_atoms)]] if not hasattr(self.gromosTop, "LJEXCEPTIONS"): - self.gromosTop.add_block(blocktitle="LJEXCEPTIONS", content=['0','']) + self.gromosTop.add_block(blocktitle="LJEXCEPTIONS", content=["0", ""]) if not hasattr(self.gromosTop, "SOLVENTATOM"): - self.gromosTop.add_block(blocktitle="SOLVENTATOM", content=['0','']) + self.gromosTop.add_block(blocktitle="SOLVENTATOM", content=["0", ""]) if not hasattr(self.gromosTop, "SOLVENTCONSTR"): - self.gromosTop.add_block(blocktitle="SOLVENTCONSTR", content=['0','']) + self.gromosTop.add_block(blocktitle="SOLVENTCONSTR", content=["0", ""]) if not hasattr(self.gromosTop, "TOPVERSION"): - self.gromosTop.add_block(blocktitle="TOPVERSION", content=['2.0']) + self.gromosTop.add_block(blocktitle="TOPVERSION", content=["2.0"]) if not hasattr(self.gromosTop, "PHYSICALCONSTANTS"): self.gromosTop.add_block(blocktitle="PHYSICALCONSTANTS", content=[""]) def convert(self): - #print OpenFF warning in Title + # print OpenFF warning in Title titleString = "" titleString += "\n\tname: " + self.openFFmolecule.name + "\t hill_formula: " + self.openFFmolecule.hill_formula - titleString += "\n\t" + 40*"-" + "\n\t| created from OpenForceField topology |\n\t| use Amber Block for OpenFF topology! |\n\t" + 40*"-"+"\n" + titleString += ( + "\n\t" + + 40 * "-" + + "\n\t| created from OpenForceField topology |\n\t| use Amber Block for OpenFF topology! |\n\t" + + 40 * "-" + + "\n" + ) if hasattr(self.gromosTop, "TITLE"): self.gromosTop.TITLE.content += [titleString] else: self.gromosTop.add_block(blocktitle="TITLE", content=[titleString]) - #Do all the conversions + # Do all the conversions self.convertResname() self.convertBonds() self.convertAngles() diff --git a/pygromos/files/gromos_system/ff/serenityff/serenityff.py b/pygromos/files/gromos_system/ff/serenityff/serenityff.py index f243709e..10f1edae 100644 --- a/pygromos/files/gromos_system/ff/serenityff/serenityff.py +++ b/pygromos/files/gromos_system/ff/serenityff/serenityff.py @@ -10,25 +10,33 @@ # general imports import collections, importlib from simtk import unit -#import math -#rdkit imports +# import math + +# rdkit imports from rdkit import Chem -#pygromos imports +# pygromos imports from pygromos.files.topology.top import Top from pygromos.files.gromos_system.ff.serenityff.serenityff_data import serenityff_C12, serenityff_C6 from pygromos.files.gromos_system.ff.forcefield_system import forcefield_system -if(importlib.util.find_spec("openff") == None): +if importlib.util.find_spec("openff") == None: raise ImportError("SerenityFF is not enabled without openFF toolkit package! Please install openFF toolkit.") else: from openff.toolkit.topology import Molecule from pygromos.files.gromos_system.ff.openforcefield2gromos import openforcefield2gromos -class serenityff(): - def __init__(self, mol:Chem.rdchem.Mol, forcefield:forcefield_system or str = None, top:Top = None, mol_name=None, develop=False): +class serenityff: + def __init__( + self, + mol: Chem.rdchem.Mol, + forcefield: forcefield_system or str = None, + top: Top = None, + mol_name=None, + develop=False, + ): self.serenityFFelements = ["H", "C", "N", "O", "F", "S", "Br", "I"] self.C6_pattern = collections.defaultdict(list) self.C12_pattern = collections.defaultdict(list) @@ -50,14 +58,14 @@ def __init__(self, mol:Chem.rdchem.Mol, forcefield:forcefield_system or str = No self.off2g = openforcefield2gromos(openFFmolecule=self.offmol, gromosTop=self.top, forcefield=forcefield) self.develop = develop - def read_pattern(self, C6orC12:str = "C6"): + def read_pattern(self, C6orC12: str = "C6"): for element in self.serenityFFelements: if C6orC12 == "C6": folder = serenityff_C6 else: folder = serenityff_C12 try: - infile = open(folder+element+".dat", 'r') + infile = open(folder + element + ".dat", "r") for line in infile: content = line.strip().split() if C6orC12 == "C6": @@ -68,34 +76,32 @@ def read_pattern(self, C6orC12:str = "C6"): except: raise Exception("WIP") - def _pattern_matching_for_one_element(self, element:str="H") -> dict(): - #TODO: add C12 support + def _pattern_matching_for_one_element(self, element: str = "H") -> dict(): + # TODO: add C12 support return_dict = collections.defaultdict(list) for pattern in reversed(self.C6_pattern[element]): - #create pattern and init some variables + # create pattern and init some variables mol_pattern = Chem.MolFromSmarts(pattern[0]) idx = 0 idx_in_rdkmol = 0 - #find the atom for which the pattern was made + # find the atom for which the pattern was made for atom in mol_pattern.GetAtoms(): if atom.GetAtomMapNum() == 1: idx = atom.GetIdx() - #get all matches + # get all matches matches = self.mol.GetSubstructMatches(mol_pattern, uniquify=False) if len(matches) >= 1: for match in matches: idx_in_rdkmol = match[idx] return_dict[idx_in_rdkmol] = [element + str(pattern[1]), pattern[2]] return return_dict - - def get_LJ_parameters(self) -> dict: return_dict = collections.defaultdict(list) if self.develop: - #get all elements in self.mol + # get all elements in self.mol contained_elements_set = set() for atom in self.mol.GetAtoms(): element = atom.GetSymbol() @@ -103,12 +109,14 @@ def get_LJ_parameters(self) -> dict: # pattern matching for all elements contained in self.mol for element in contained_elements_set: - return_dict.update(self._pattern_matching_for_one_element(element=element)) + return_dict.update(self._pattern_matching_for_one_element(element=element)) else: raise NotImplementedError("WIP") return return_dict - def create_serenityff_nonBonded(self, C12_input={'H':0.0,'C':0.0}, partial_charges=collections.defaultdict(float)): + def create_serenityff_nonBonded( + self, C12_input={"H": 0.0, "C": 0.0}, partial_charges=collections.defaultdict(float) + ): if self.develop: self.read_pattern() c6dict = self.get_LJ_parameters() @@ -124,40 +132,55 @@ def create_serenityff_nonBonded(self, C12_input={'H':0.0,'C':0.0}, partial_charg element_symbol = self.mol.GetAtomWithIdx(int(key[0])).GetSymbol() panm_dict[element_symbol] += 1 PANM = element_symbol + str(panm_dict[element_symbol]) - IAC = 0 #will not be used if we use automatic + IAC = 0 # will not be used if we use automatic MASS = self.off2g.openFFmolecule.atoms[int(key[0])].mass.value_in_unit(unit.dalton) CG = 0 if self.develop: CG = partial_charges[int(key[0])] if ATNM == self.mol.GetNumAtoms(): CGC = 1 - else: + else: CGC = 0 if str(key[0]) in self.off2g.exclusionList13: openFFexList13 = list(self.off2g.exclusionList13[str(key[0])]) - INE = [int(x)+1 for x in openFFexList13] + INE = [int(x) + 1 for x in openFFexList13] else: INE = list() if str(key[0]) in self.off2g.exclusionList14: openFFexList14 = list(self.off2g.exclusionList14[str(key[0])]) - INE14 = [int(x)+1 for x in openFFexList14] + INE14 = [int(x) + 1 for x in openFFexList14] else: INE14 = list() epsilon = float(force.epsilon.value_in_unit(unit.kilojoule_per_mole)) rmin = 2 * force.rmin_half.value_in_unit(unit.nanometer) - C6 = (float(c6dict[key[0]][1]))**2 + C6 = (float(c6dict[key[0]][1])) ** 2 CS6 = 0.5 * C6 C12 = epsilon * (rmin**12) if self.develop: C12 = C12_input[(c6dict[key[0]][0])] CS12 = 0.5 * C12 IACname = c6dict[key[0]][0] - self.off2g.gromosTop.add_new_atom(ATNM=ATNM, MRES=MRES, PANM=PANM, IAC=IAC, MASS=MASS, CG=CG, CGC=CGC, INE=INE, INE14=INE14, C6=C6, C12=C12, CS6=CS6, CS12=CS12, IACname=IACname) + self.off2g.gromosTop.add_new_atom( + ATNM=ATNM, + MRES=MRES, + PANM=PANM, + IAC=IAC, + MASS=MASS, + CG=CG, + CGC=CGC, + INE=INE, + INE14=INE14, + C6=C6, + C12=C12, + CS6=CS6, + CS12=CS12, + IACname=IACname, + ) moleculeItr += 1 else: raise NotImplementedError("WIP") - def create_top(self, C12_input={'H':0.0,'C':0.0}, partial_charges=collections.defaultdict(float)): + def create_top(self, C12_input={"H": 0.0, "C": 0.0}, partial_charges=collections.defaultdict(float)): self.off2g.convertResname() self.off2g.convertBonds() self.off2g.convertAngles() @@ -166,4 +189,3 @@ def create_top(self, C12_input={'H':0.0,'C':0.0}, partial_charges=collections.de self.off2g.convert_other_stuff() self.create_serenityff_nonBonded(C12_input=C12_input, partial_charges=partial_charges) self.top = self.off2g.gromosTop - diff --git a/pygromos/files/gromos_system/ff/serenityff/serenityff_data/__init__.py b/pygromos/files/gromos_system/ff/serenityff/serenityff_data/__init__.py index 2aa319ad..29c8b47c 100644 --- a/pygromos/files/gromos_system/ff/serenityff/serenityff_data/__init__.py +++ b/pygromos/files/gromos_system/ff/serenityff/serenityff_data/__init__.py @@ -1,3 +1,4 @@ import os + serenityff_C6 = os.path.dirname(__file__) + "/C6/" serenityff_C12 = os.path.dirname(__file__) + "/C12/" diff --git a/pygromos/files/gromos_system/ff/solvents/Solvents.py b/pygromos/files/gromos_system/ff/solvents/Solvents.py index e3d0a0ac..b07837cd 100644 --- a/pygromos/files/gromos_system/ff/solvents/Solvents.py +++ b/pygromos/files/gromos_system/ff/solvents/Solvents.py @@ -2,57 +2,60 @@ This module collects all solvent subclasses for python file and information management with gromos """ -class Solvent(): + + +class Solvent: """Solvent - This class is giving the needed solvent infofmation for gromos in an obj. - #TODO: CONFs & TOPO in data + This class is giving the needed solvent infofmation for gromos in an obj. + #TODO: CONFs & TOPO in data """ - name:str = None - coord_file_path:str = None - def __init__(self, name:str=None, coord_file:str=None): + name: str = None + coord_file_path: str = None + + def __init__(self, name: str = None, coord_file: str = None): - if(name!=None): + if name != None: self.name = name self.coord_file_path = coord_file else: - raise IOError("DID not get correct Constructor arguments in "+self.__class__.name) + raise IOError("DID not get correct Constructor arguments in " + self.__class__.name) - def _return_all_paths(self)->list: + def _return_all_paths(self) -> list: coll = [] - if(self.coord_file_path != None): + if self.coord_file_path != None: coll.append(self.coord_file_path) return coll class H2O(Solvent): - def __init__(self, coord_file_path:str=None): + def __init__(self, coord_file_path: str = None): - if(coord_file_path!=None): + if coord_file_path != None: super().__init__(name="H2O") self.coord_file_path = coord_file_path - self.atomNum=3 + self.atomNum = 3 else: - raise IOError("DID not get correct Constructor arguments in "+self.__class__.name) + raise IOError("DID not get correct Constructor arguments in " + self.__class__.name) class CHCL3(Solvent): - def __init__(self, coord_file_path:str=None): + def __init__(self, coord_file_path: str = None): - if(coord_file_path!=None): + if coord_file_path != None: super().__init__(name="CHCL3") self.coord_file_path = coord_file_path - self.atomNum=5 + self.atomNum = 5 else: - raise IOError("DID not get correct Constructor arguments in "+self.__class__.name) + raise IOError("DID not get correct Constructor arguments in " + self.__class__.name) class DMSO(Solvent): - def __init__(self, coord_file_path:str=None): + def __init__(self, coord_file_path: str = None): - if(coord_file_path!=None): + if coord_file_path != None: super().__init__(name="DMSO") self.coord_file_path = coord_file_path - self.atomNum=4 + self.atomNum = 4 else: - raise IOError("DID not get correct Constructor arguments in "+self.__class__.name) \ No newline at end of file + raise IOError("DID not get correct Constructor arguments in " + self.__class__.name) diff --git a/pygromos/files/gromos_system/ff/solvents/_base.py b/pygromos/files/gromos_system/ff/solvents/_base.py index 1d50b50b..f8da237f 100644 --- a/pygromos/files/gromos_system/ff/solvents/_base.py +++ b/pygromos/files/gromos_system/ff/solvents/_base.py @@ -1,46 +1,59 @@ from typing import List, Dict + class _fileManagment_base_class: def __init__(self): pass - - def __str__(self, offset:str="" )->str: - msg = offset+self.__class__.__name__+"\n" + def __str__(self, offset: str = "") -> str: + msg = offset + self.__class__.__name__ + "\n" for key, value in vars(self).items(): - if (not key.startswith("_") and not issubclass(value.__class__, _fileManagment_base_class)): - if(isinstance(value, List)): - msg += offset+"\t"+key + ": " + "\n\t".join(map(str, value)) + "\n" + if not key.startswith("_") and not issubclass(value.__class__, _fileManagment_base_class): + if isinstance(value, List): + msg += offset + "\t" + key + ": " + "\n\t".join(map(str, value)) + "\n" else: - msg += offset+"\t"+key + ": " + str(value) + "\n" - elif (issubclass(value.__class__, _fileManagment_base_class)): - msg += offset+"\t"+key+": \n"+value.__str__(offset=offset+"\t\t")+"\n" + msg += offset + "\t" + key + ": " + str(value) + "\n" + elif issubclass(value.__class__, _fileManagment_base_class): + msg += offset + "\t" + key + ": \n" + value.__str__(offset=offset + "\t\t") + "\n" return msg - - def get_script_generation_command(self, var_name:str=None, var_prefixes="system")->str: - - if(isinstance(var_name, type(None))): - var_name=var_prefixes + self.__class__.__name__ - - gen_cmd = "#Generate "+ self.__class__.__name__+ "\n" - gen_cmd += "from " + self.__module__ + " import "+ self.__class__.__name__+" as "+ self.__class__.__name__+"_obj"+ "\n" - constr_str = var_name+" = " + self.__class__.__name__ + "_obj( " + def get_script_generation_command(self, var_name: str = None, var_prefixes="system") -> str: + + if isinstance(var_name, type(None)): + var_name = var_prefixes + self.__class__.__name__ + + gen_cmd = "#Generate " + self.__class__.__name__ + "\n" + gen_cmd += ( + "from " + + self.__module__ + + " import " + + self.__class__.__name__ + + " as " + + self.__class__.__name__ + + "_obj" + + "\n" + ) + constr_str = var_name + " = " + self.__class__.__name__ + "_obj( " for key, value in vars(self).items(): - if (not key.startswith("_") and not issubclass(value.__class__, _fileManagment_base_class)): + if not key.startswith("_") and not issubclass(value.__class__, _fileManagment_base_class): - if(isinstance(value, List)): - gen_cmd += var_prefixes + "_" + key + " = [ \"" + "\",\n\t\"".join(map(str,value)) + "\" ]\n" + if isinstance(value, List): + gen_cmd += var_prefixes + "_" + key + ' = [ "' + '",\n\t"'.join(map(str, value)) + '" ]\n' else: - gen_cmd += var_prefixes + "_" + key + " = \"" + str(value) + "\"\n" + gen_cmd += var_prefixes + "_" + key + ' = "' + str(value) + '"\n' constr_str += key + "=" + var_prefixes + "_" + key + ", " - elif (issubclass(value.__class__, _fileManagment_base_class)): - gen_cmd += "\n"+value.get_script_generation_command(var_name= var_prefixes + "_" + value.__class__.__name__, - var_prefixes=var_prefixes)+ "\n" + elif issubclass(value.__class__, _fileManagment_base_class): + gen_cmd += ( + "\n" + + value.get_script_generation_command( + var_name=var_prefixes + "_" + value.__class__.__name__, var_prefixes=var_prefixes + ) + + "\n" + ) constr_str += key + "=" + var_prefixes + "_" + value.__class__.__name__ + ", " constr_str += ")\n" - cmd = gen_cmd+"\n\n"+constr_str+"\n" + cmd = gen_cmd + "\n\n" + constr_str + "\n" - return cmd \ No newline at end of file + return cmd diff --git a/pygromos/files/gromos_system/gromos_system.py b/pygromos/files/gromos_system/gromos_system.py index abe39b9e..1704ee2d 100644 --- a/pygromos/files/gromos_system/gromos_system.py +++ b/pygromos/files/gromos_system/gromos_system.py @@ -4,11 +4,12 @@ Description: -This is a super class for the collection of all Gromos files used inside a project. +This is a super class for the collection of all Gromos files used inside a project. Bundle files with the system's topology, coordinates, input parameters, etc. and -start your simulations from here. +start your simulations from here. Author: Marc Lehner, Benjamin Ries, Felix Pultar +test """ # imports @@ -40,14 +41,15 @@ import pickle, io -if (importlib.util.find_spec("rdkit") != None): +if importlib.util.find_spec("rdkit") != None: from rdkit import Chem from rdkit.Chem import AllChem + has_rdkit = True else: has_rdkit = False -if (importlib.util.find_spec("openff") != None): +if importlib.util.find_spec("openff") != None: from openff.toolkit.topology import Molecule from pygromos.files.gromos_system.ff.openforcefield2gromos import openforcefield2gromos from pygromos.files.gromos_system.ff.serenityff.serenityff import serenityff @@ -56,49 +58,68 @@ else: has_openff = False -skip = {"solute_info":cnf.solute_infos, - "protein_info":cnf.protein_infos, - "non_ligand_info": cnf.non_ligand_infos, - "solvent_info": cnf.solvent_infos} - -class Gromos_System(): - required_files = {"imd": Imd, - "top": Top, - "cnf": Cnf} - optional_files = {"disres": Disres, - "ptp": Pertubation_topology, - "posres": Position_Restraints, - "refpos": Reference_Position, - "qmmm": QMMM} - - residue_list:Dict - solute_info:cnf.solute_infos - protein_info:cnf.protein_infos - non_ligand_info:cnf.non_ligand_infos - solvent_info:cnf.solvent_infos - checkpoint_path:str - _future_promise:bool #for interest if multiple jobs shall be chained. - _future_promised_files:list - - _single_multibath:bool - _single_energy_group:bool - - _gromosPP_bin_dir : Union[None, str] - _gromosXX_bin_dir : Union[None, str] - _gromosPP : GromosPP - _gromosXX : GromosXX - - def __init__(self, work_folder: str, system_name: str, in_smiles: str = None, - in_top_path: str = None, in_cnf_path: str = None, in_imd_path: str = None, - in_disres_path: str = None, in_ptp_path: str = None, in_posres_path:str = None, in_refpos_path:str=None, - in_qmmm_path: str = None, in_gromosXX_bin_dir:str = None, in_gromosPP_bin_dir:str=None, - rdkitMol: Chem.rdchem.Mol = None, readIn=True, Forcefield:forcefield_system=forcefield_system(), - auto_convert:bool=False, adapt_imd_automatically:bool=True, verbose:bool=False): +skip = { + "solute_info": cnf.solute_infos, + "protein_info": cnf.protein_infos, + "non_ligand_info": cnf.non_ligand_infos, + "solvent_info": cnf.solvent_infos, +} + + +class Gromos_System: + required_files = {"imd": Imd, "top": Top, "cnf": Cnf} + optional_files = { + "disres": Disres, + "ptp": Pertubation_topology, + "posres": Position_Restraints, + "refpos": Reference_Position, + "qmmm": QMMM, + } + + residue_list: Dict + solute_info: cnf.solute_infos + protein_info: cnf.protein_infos + non_ligand_info: cnf.non_ligand_infos + solvent_info: cnf.solvent_infos + checkpoint_path: str + _future_promise: bool # for interest if multiple jobs shall be chained. + _future_promised_files: list + + _single_multibath: bool + _single_energy_group: bool + + _gromosPP_bin_dir: Union[None, str] + _gromosXX_bin_dir: Union[None, str] + _gromosPP: GromosPP + _gromosXX: GromosXX + + def __init__( + self, + work_folder: str, + system_name: str, + rdkitMol: Chem.rdchem.Mol = None, + readIn=True, + Forcefield: forcefield_system = forcefield_system(), + auto_convert: bool = False, + adapt_imd_automatically: bool = True, + verbose: bool = False, + in_smiles: str = None, + in_top_path: str = None, + in_cnf_path: str = None, + in_imd_path: str = None, + in_disres_path: str = None, + in_ptp_path: str = None, + in_posres_path: str = None, + in_refpos_path: str = None, + in_qmmm_path: str = None, + in_gromosXX_bin_dir: str = None, + in_gromosPP_bin_dir: str = None, + ): """ - The Gromos_System class is the central unit of PyGromosTools for files and states. + The Gromos_System class is the central unit of PyGromosTools for files and states. With this class all files can be read-in or the files can be automatically generated from smiles. Additionally to that can all gromos++ functions be used from the Gromos System, so system generation can be easily accomplished. - + Parameters ---------- @@ -146,7 +167,6 @@ def __init__(self, work_folder: str, system_name: str, in_smiles: str = None, Warning Rises warning if files are not present. """ - self.hasData = False self._name = system_name @@ -166,31 +186,39 @@ def __init__(self, work_folder: str, system_name: str, in_smiles: str = None, self.gromosPP = in_gromosPP_bin_dir self.gromosXX = in_gromosXX_bin_dir - #add functions of gromosPP to system + # add functions of gromosPP to system self.__bind_gromosPPFuncs() ## For HPC-Queueing - self._future_promise= False + self._future_promise = False self._future_promised_files = [] if (in_smiles == None and rdkitMol == None) or readIn == False: - if verbose: warnings.warn("No data provided to gromos_system\nmanual work needed") + if verbose: + warnings.warn("No data provided to gromos_system\nmanual work needed") # import files: - file_mapping = {"imd": in_imd_path, - "top": in_top_path, "ptp": in_ptp_path, - "cnf": in_cnf_path, - "disres": in_disres_path, - "posres": in_posres_path, - "refpos": in_refpos_path, - "qmmm": in_qmmm_path - } + file_mapping = { + "imd": in_imd_path, + "top": in_top_path, + "ptp": in_ptp_path, + "cnf": in_cnf_path, + "disres": in_disres_path, + "posres": in_posres_path, + "refpos": in_refpos_path, + "qmmm": in_qmmm_path, + } self.parse_attribute_files(file_mapping, readIn=readIn, verbose=verbose) ##System Information: - if(not self._cnf._future_file): - self.residue_list, self.solute_info, self.protein_info, self.non_ligand_info, self.solvent_info = self._cnf.get_system_information( - not_ligand_residues=[]) + if not self._cnf._future_file: + ( + self.residue_list, + self.solute_info, + self.protein_info, + self.non_ligand_info, + self.solvent_info, + ) = self._cnf.get_system_information(not_ligand_residues=[]) else: self.residue_list = None self.solute_info = None @@ -220,75 +248,137 @@ def __init__(self, work_folder: str, system_name: str, in_smiles: str = None, if in_cnf_path is None and type(self.mol) == Chem.rdchem.Mol and self.mol.GetNumAtoms() >= 1: self.cnf = Cnf(in_value=self.mol) - #TODO: fix ugly workaround for cnf from rdkit with GROMOS FFs - if (self.Forcefield.name == "2016H66" or self.Forcefield.name == "54A7"): - if self.gromosPP is not None and bash.command_exists(self.gromosPP.bin+"/pdb2g96"): + # TODO: fix ugly workaround for cnf from rdkit with GROMOS FFs + if self.Forcefield.name == "2016H66" or self.Forcefield.name == "54A7": + if self.gromosPP is not None and bash.command_exists(self.gromosPP.bin + "/pdb2g96"): try: from pygromos.files.blocks.coord_blocks import atomP - new_pos = [atomP(xp=atom.xp, yp=atom.yp, zp=atom.zp, - resID=atom.resID, atomType=atom.atomType+str(i+1), atomID=atom.atomID, - resName=self.Forcefield.mol_name) for i, atom in enumerate(self.cnf.POSITION)] + + new_pos = [ + atomP( + xp=atom.xp, + yp=atom.yp, + zp=atom.zp, + resID=atom.resID, + atomType=atom.atomType + str(i + 1), + atomID=atom.atomID, + resName=self.Forcefield.mol_name, + ) + for i, atom in enumerate(self.cnf.POSITION) + ] self.cnf.POSITION = new_pos - self.cnf.write_pdb(self.work_folder+"/tmp.pdb") - self.pdb2gromos(self.work_folder+"/tmp.pdb") + self.cnf.write_pdb(self.work_folder + "/tmp.pdb") + self.pdb2gromos(self.work_folder + "/tmp.pdb") self.add_hydrogens() except: raise Warning("Could not convert cnf from rdkit to gromos, will use rdkit cnf") - - + # decide if the imd should be adapted (force groups etc.) # assert if the respective option is activated and cnf/imd files do actually exist - if(self.adapt_imd_automatically and not self._cnf._future_file and not self.imd._future_file): + if self.adapt_imd_automatically and not self._cnf._future_file and not self.imd._future_file: self.adapt_imd() - #misc - self._all_files_key = list(map(lambda x: "_"+x, self.required_files.keys())) - self._all_files_key.extend(list(map(lambda x: "_"+x, self.optional_files.keys()))) + # misc + self._all_files_key = list(map(lambda x: "_" + x, self.required_files.keys())) + self._all_files_key.extend(list(map(lambda x: "_" + x, self.optional_files.keys()))) self._all_files = copy.copy(self.required_files) self._all_files.update(copy.copy(self.optional_files)) - def __str__(self)->str: + def __str__(self) -> str: msg = "\n" msg += "GROMOS SYSTEM: " + self.name + "\n" msg += utils.spacer msg += "WORKDIR: " + self._work_folder + "\n" msg += "LAST CHECKPOINT: " + str(self.checkpoint_path) + "\n" msg += "\n" - msg += "GromosXX_bin: " + str(self.gromosXX_bin_dir) + "\n" + msg += "GromosXX_bin: " + str(self.gromosXX_bin_dir) + "\n" msg += "GromosPP_bin: " + str(self.gromosPP_bin_dir) + "\n" - msg += "FILES: \n\t"+"\n\t".join([str(key)+": "+str(val) for key,val in self.all_file_paths.items()])+"\n" - msg += "FUTURE PROMISE: "+str(self._future_promise)+"\n" - if(hasattr(self, "solute_info") + msg += ( + "FILES: \n\t" + "\n\t".join([str(key) + ": " + str(val) for key, val in self.all_file_paths.items()]) + "\n" + ) + msg += "FUTURE PROMISE: " + str(self._future_promise) + "\n" + if ( + hasattr(self, "solute_info") or hasattr(self, "protein_info") or hasattr(self, "non_ligand_info") - or hasattr(self, "solvent_info")): + or hasattr(self, "solvent_info") + ): msg += "SYSTEM: \n" - if(hasattr(self, "protein_info") and not self.protein_info is None and self.protein_info.number_of_residues > 0): - if(hasattr(self, "protein_info") and not self.protein_info is None): - #+" resIDs: "+str(self.protein_info.residues[0])+"-"+str(self.protein_info.residues[-1]) - msg += "\tPROTEIN:\t"+str(self.protein_info.name)+" nresidues: "+str(self.protein_info.number_of_residues)+" natoms: "+str(self.protein_info.number_of_atoms)+"\n" - if(hasattr(self, "solute_info") and not self.solute_info is None): - msg += "\tLIGANDS:\t" + str(self.solute_info.names) + " resID: " + str(self.solute_info.positions) + " natoms: " + str(self.solute_info.number_of_atoms) + "\n" - if (hasattr(self, "non_ligand_info") and not self.non_ligand_info is None): - #+" resID: "+str(self.non_ligand_info.positions) - msg += "\tNon-LIGANDS:\t"+str(self.non_ligand_info.names)+" nmolecules: "+str(self.non_ligand_info.number)+" natoms: "+str(self.non_ligand_info.number_of_atoms)+"\n" - if (hasattr(self, "solvent_info") and not self.solvent_info is None): - #" resIDs: "+str(self.solvent_info.positions[0])+"-"+str(self.solvent_info.positions[-1])+ - msg += "\tSOLVENT:\t"+str(self.solvent_info.name)+" nmolecules: "+str(self.solvent_info.number)+" natoms: "+str(self.solvent_info.number_of_atoms)+"\n" + if ( + hasattr(self, "protein_info") + and not self.protein_info is None + and self.protein_info.number_of_residues > 0 + ): + if hasattr(self, "protein_info") and not self.protein_info is None: + # +" resIDs: "+str(self.protein_info.residues[0])+"-"+str(self.protein_info.residues[-1]) + msg += ( + "\tPROTEIN:\t" + + str(self.protein_info.name) + + " nresidues: " + + str(self.protein_info.number_of_residues) + + " natoms: " + + str(self.protein_info.number_of_atoms) + + "\n" + ) + if hasattr(self, "solute_info") and not self.solute_info is None: + msg += ( + "\tLIGANDS:\t" + + str(self.solute_info.names) + + " resID: " + + str(self.solute_info.positions) + + " natoms: " + + str(self.solute_info.number_of_atoms) + + "\n" + ) + if hasattr(self, "non_ligand_info") and not self.non_ligand_info is None: + # +" resID: "+str(self.non_ligand_info.positions) + msg += ( + "\tNon-LIGANDS:\t" + + str(self.non_ligand_info.names) + + " nmolecules: " + + str(self.non_ligand_info.number) + + " natoms: " + + str(self.non_ligand_info.number_of_atoms) + + "\n" + ) + if hasattr(self, "solvent_info") and not self.solvent_info is None: + # " resIDs: "+str(self.solvent_info.positions[0])+"-"+str(self.solvent_info.positions[-1])+ + msg += ( + "\tSOLVENT:\t" + + str(self.solvent_info.name) + + " nmolecules: " + + str(self.solvent_info.number) + + " natoms: " + + str(self.solvent_info.number_of_atoms) + + "\n" + ) else: - if (hasattr(self, "solute_info") and not self.solute_info is None): - msg += "\tSolute:\t" + str(self.solute_info.names) + " resID: " + str( - self.solute_info.positions) + " natoms: " + str( - self.solute_info.number_of_atoms) + "\n" - if (hasattr(self, "solvent_info") and not self.solvent_info is None): + if hasattr(self, "solute_info") and not self.solute_info is None: + msg += ( + "\tSolute:\t" + + str(self.solute_info.names) + + " resID: " + + str(self.solute_info.positions) + + " natoms: " + + str(self.solute_info.number_of_atoms) + + "\n" + ) + if hasattr(self, "solvent_info") and not self.solvent_info is None: # " resIDs: "+str(self.solvent_info.positions[0])+"-"+str(self.solvent_info.positions[-1])+ - msg += "\tSOLVENT:\t" + str(self.solvent_info.name) + " nmolecules: " + str( - self.solvent_info.number) + " natoms: " + str(self.solvent_info.number_of_atoms) + "\n" - - msg +="\n\n" + msg += ( + "\tSOLVENT:\t" + + str(self.solvent_info.name) + + " nmolecules: " + + str(self.solvent_info.number) + + " natoms: " + + str(self.solvent_info.number_of_atoms) + + "\n" + ) + + msg += "\n\n" return msg - def __repr__(self)-> str: + def __repr__(self) -> str: return str(self) def __getstate__(self): @@ -297,11 +387,11 @@ def __getstate__(self): remove the non trivial pickling parts """ attribute_dict = self.__dict__ - new_dict ={} + new_dict = {} for key in attribute_dict.keys(): - if (not isinstance(attribute_dict[key], Callable) and not key in skip): - new_dict.update({key:attribute_dict[key]}) - elif(not attribute_dict[key] is None and key in skip): + if not isinstance(attribute_dict[key], Callable) and not key in skip: + new_dict.update({key: attribute_dict[key]}) + elif not attribute_dict[key] is None and key in skip: new_dict.update({key: attribute_dict[key]._asdict()}) else: new_dict.update({key: None}) @@ -311,12 +401,12 @@ def __getstate__(self): def __setstate__(self, state): self.__dict__ = state for key in skip: - if(key in self.__dict__ ) and not self.__dict__[key] is None: + if (key in self.__dict__) and not self.__dict__[key] is None: setattr(self, key, skip[key](**self.__dict__[key])) - #misc - self._all_files_key = list(map(lambda x: "_"+x, self.required_files.keys())) - self._all_files_key.extend(list(map(lambda x: "_"+x, self.optional_files.keys()))) + # misc + self._all_files_key = list(map(lambda x: "_" + x, self.required_files.keys())) + self._all_files_key.extend(list(map(lambda x: "_" + x, self.optional_files.keys()))) self._all_files = copy.copy(self.required_files) self._all_files.update(copy.copy(self.optional_files)) @@ -325,7 +415,7 @@ def __setstate__(self, state): self.__bind_gromosPPFuncs() - #are promised files now present? + # are promised files now present? self._check_promises() def __deepcopy__(self, memo): @@ -334,36 +424,35 @@ def __deepcopy__(self, memo): copy_obj.__setstate__(copy.deepcopy(self.__getstate__())) return copy_obj - - def copy(self, no_traj:bool=True): + def copy(self, no_traj: bool = True): return copy.deepcopy(self) - def copy(self): return copy.deepcopy(self) """ Properties """ + @property - def work_folder(self)->str: + def work_folder(self) -> str: return self._work_folder @work_folder.setter - def work_folder(self, work_folder:str): + def work_folder(self, work_folder: str): self._work_folder = work_folder self._update_all_file_paths() # Updates the work folder without updating all file paths - def work_folder_no_update(self, work_folder:str): + def work_folder_no_update(self, work_folder: str): self._work_folder = work_folder @property - def name(self)->str: + def name(self) -> str: return self._name @name.setter - def name(self, system_name:str): + def name(self, system_name: str): self._name = system_name @property @@ -376,8 +465,11 @@ def all_files(self) -> Dict[str, _general_gromos_file]: """ self._all_files_key = list(self.required_files.keys()) self._all_files_key.extend(list(self.optional_files.keys())) - self._all_files = {key: getattr(self, key) for key in self._all_files_key if - (hasattr(self, key) and (not getattr(self, key) is None))} + self._all_files = { + key: getattr(self, key) + for key in self._all_files_key + if (hasattr(self, key) and (not getattr(self, key) is None)) + } return self._all_files @property @@ -390,240 +482,249 @@ def all_file_paths(self) -> Dict[str, str]: """ self._all_files_key = list(self.required_files.keys()) self._all_files_key.extend(list(self.optional_files.keys())) - self._all_file_paths = {key: getattr(self, key).path for key in self._all_files_key if - (hasattr(self, key) and (not getattr(self, key) is None))} + self._all_file_paths = { + key: getattr(self, key).path + for key in self._all_files_key + if (hasattr(self, key) and (not getattr(self, key) is None)) + } return self._all_file_paths @property - def top(self)->Top: + def top(self) -> Top: return self._top @top.setter - def top(self, input_value:Union[str, Top]): - if(isinstance(input_value, str)): - if(os.path.exists(input_value)): + def top(self, input_value: Union[str, Top]): + if isinstance(input_value, str): + if os.path.exists(input_value): self._top = Top(in_value=input_value) - elif(self._future_promise): + elif self._future_promise: self._top = Top(in_value=input_value, _future_file=self._future_promise) self._future_promised_files.append("top") self._future_promise = True else: - raise FileNotFoundError("Could not find file: "+str(input_value)) - elif(isinstance(input_value, Top)): + raise FileNotFoundError("Could not find file: " + str(input_value)) + elif isinstance(input_value, Top): self._top = input_value else: raise ValueError("Could not parse input type: " + str(type(input_value)) + " " + str(input_value)) @property - def cnf(self)->Cnf: + def cnf(self) -> Cnf: return self._cnf @cnf.setter - def cnf(self, input_value:Union[str, Cnf]): - if(isinstance(input_value, str)): - if(os.path.exists(input_value)): + def cnf(self, input_value: Union[str, Cnf]): + if isinstance(input_value, str): + if os.path.exists(input_value): self._cnf = Cnf(in_value=input_value, _future_file=False) self.residue_list = self._cnf.get_residues() - self.residue_list, self.solute_info, self.protein_info, self.non_ligand_info, self.solvent_info = self._cnf.get_system_information(not_ligand_residues=[]) - - elif(self._future_promise): + ( + self.residue_list, + self.solute_info, + self.protein_info, + self.non_ligand_info, + self.solvent_info, + ) = self._cnf.get_system_information(not_ligand_residues=[]) + + elif self._future_promise: self._cnf = Cnf(in_value=input_value, _future_file=self._future_promise) self._future_promised_files.append("cnf") self._future_promise = True else: - raise FileNotFoundError("Could not find file: "+str(input_value)) - elif(isinstance(input_value, Cnf)): + raise FileNotFoundError("Could not find file: " + str(input_value)) + elif isinstance(input_value, Cnf): self._cnf = input_value else: raise ValueError("Could not parse input type: " + str(type(input_value)) + " " + str(input_value)) @property - def imd(self)->Imd: + def imd(self) -> Imd: return self._imd @imd.setter - def imd(self, input_value:Union[str, Imd]): + def imd(self, input_value: Union[str, Imd]): # Make sure the new Imd (str or Imd object) is updated only if the option # has been enabled (adapt_imd_automatically) and actually has coordinates # data that could be used to adapt the imd - is_adaptable = self.adapt_imd_automatically and not (self.cnf._future_file - and (self.residue_list is None or self.solute_info is None)) - if(isinstance(input_value, str)): - if(os.path.exists(input_value) or self._future_promise): + is_adaptable = self.adapt_imd_automatically and not ( + self.cnf._future_file and (self.residue_list is None or self.solute_info is None) + ) + if isinstance(input_value, str): + if os.path.exists(input_value) or self._future_promise: self._imd = Imd(in_value=input_value) - if (is_adaptable): + if is_adaptable: self.adapt_imd() - elif(self._future_promise): + elif self._future_promise: self._imd = Imd(in_value=input_value, _future_file=self._future_promise) self._future_promised_files.append("imd") self._future_promise = True else: - raise FileNotFoundError("Could not find file: "+str(input_value)) - elif(isinstance(input_value, Imd)): + raise FileNotFoundError("Could not find file: " + str(input_value)) + elif isinstance(input_value, Imd): self._imd = input_value - if (is_adaptable): + if is_adaptable: self.adapt_imd() - elif(input_value is None): + elif input_value is None: self._imd = None else: raise ValueError("Could not parse input type: " + str(type(input_value)) + " " + str(input_value)) @property - def refpos(self)->Reference_Position: + def refpos(self) -> Reference_Position: return self._refpos @refpos.setter - def refpos(self, input_value:Union[str, Reference_Position]): - if(isinstance(input_value, str)): - if(os.path.exists(input_value) or self._future_promise): + def refpos(self, input_value: Union[str, Reference_Position]): + if isinstance(input_value, str): + if os.path.exists(input_value) or self._future_promise: self._refpos = Reference_Position(in_value=input_value) - elif(self._future_promise): + elif self._future_promise: self._refpos = Reference_Position(in_value=input_value, _future_file=self._future_promise) self._future_promised_files.append("refpos") else: - raise FileNotFoundError("Could not find file: "+str(input_value)) - elif(isinstance(input_value, Reference_Position)): + raise FileNotFoundError("Could not find file: " + str(input_value)) + elif isinstance(input_value, Reference_Position): self._refpos = input_value - elif(input_value is None): + elif input_value is None: self._refpos = None else: raise ValueError("Could not parse input type: " + str(type(input_value)) + " " + str(input_value)) @property - def posres(self)->Position_Restraints: + def posres(self) -> Position_Restraints: return self._posres @posres.setter - def posres(self, input_value:Union[str, Position_Restraints]): - if(isinstance(input_value, str)): - if(os.path.exists(input_value) or self._future_promise): + def posres(self, input_value: Union[str, Position_Restraints]): + if isinstance(input_value, str): + if os.path.exists(input_value) or self._future_promise: self._posres = Position_Restraints(in_value=input_value) - elif(self._future_promise): + elif self._future_promise: self._posres = Position_Restraints(in_value=input_value, _future_file=self._future_promise) self._future_promised_files.append("posres") else: - raise FileNotFoundError("Could not find file: "+str(input_value)) - elif(isinstance(input_value, Position_Restraints)): + raise FileNotFoundError("Could not find file: " + str(input_value)) + elif isinstance(input_value, Position_Restraints): self._posres = input_value - elif(input_value is None): + elif input_value is None: self._posres = None else: raise ValueError("Could not parse input type: " + str(type(input_value)) + " " + str(input_value)) @property - def disres(self)->Disres: + def disres(self) -> Disres: return self._disres @disres.setter - def disres(self, input_value:Union[str, Disres]): - if(isinstance(input_value, str)): - if(os.path.exists(input_value)): + def disres(self, input_value: Union[str, Disres]): + if isinstance(input_value, str): + if os.path.exists(input_value): self._disres = Disres(in_value=input_value) else: - raise FileNotFoundError("Could not find file: "+str(input_value)) - elif(isinstance(input_value, Disres)): + raise FileNotFoundError("Could not find file: " + str(input_value)) + elif isinstance(input_value, Disres): self._disres = input_value else: raise ValueError("Could not parse input type: " + str(type(input_value)) + " " + str(input_value)) @property - def ptp(self)->Pertubation_topology: + def ptp(self) -> Pertubation_topology: return self._ptp @ptp.setter - def ptp(self, input_value:Union[str, Pertubation_topology]): - if(isinstance(input_value, str)): - if(os.path.exists(input_value)): + def ptp(self, input_value: Union[str, Pertubation_topology]): + if isinstance(input_value, str): + if os.path.exists(input_value): self._ptp = Pertubation_topology(in_value=input_value) else: - raise FileNotFoundError("Could not find file: "+str(input_value)) - elif(isinstance(input_value, Pertubation_topology)): - self._ptp = input_value + raise FileNotFoundError("Could not find file: " + str(input_value)) + elif isinstance(input_value, Pertubation_topology): + self._ptp = input_value else: raise ValueError("Could not parse input type: " + str(type(input_value)) + " " + str(input_value)) @property - def qmmm(self)->QMMM: + def qmmm(self) -> QMMM: return self._qmmm @qmmm.setter - def qmmm(self, input_value:Union[str, QMMM]): - if(isinstance(input_value, str)): - if(os.path.exists(input_value) or self._future_promise): + def qmmm(self, input_value: Union[str, QMMM]): + if isinstance(input_value, str): + if os.path.exists(input_value) or self._future_promise: self._qmmm = QMMM(in_value=input_value) else: raise FileNotFoundError("Could not find file: " + str(input_value)) - elif(isinstance(input_value, QMMM)): + elif isinstance(input_value, QMMM): self._qmmm = input_value - elif(input_value is None): + elif input_value is None: self._qmmm = None else: raise ValueError("Could not parse input type: " + str(type(input_value)) + " " + str(input_value)) - + @property - def gromosXX_bin_dir(self)->str: + def gromosXX_bin_dir(self) -> str: return self._gromosXX_bin_dir @gromosXX_bin_dir.setter - def gromosXX_bin_dir(self, path:str): + def gromosXX_bin_dir(self, path: str): self.gromosXX = path @property - def gromosPP_bin_dir(self)->str: + def gromosPP_bin_dir(self) -> str: return self._gromosPP_bin_dir @gromosPP_bin_dir.setter - def gromosPP_bin_dir(self, path:str): + def gromosPP_bin_dir(self, path: str): self.gromosPP = path - + @property - def gromosXX(self)->GromosXX: + def gromosXX(self) -> GromosXX: return self._gromosXX @gromosXX.setter - def gromosXX(self, input_value:Union[str, GromosXX]): - if(isinstance(input_value, str)): + def gromosXX(self, input_value: Union[str, GromosXX]): + if isinstance(input_value, str): # check if path to GromosXX binary is a valid directory and if md binary is present - if(bash.directory_exists(input_value) and bash.command_exists(f"{input_value}/md")): + if bash.directory_exists(input_value) and bash.command_exists(f"{input_value}/md"): self._gromosXX = GromosXX(gromosXX_bin_dir=input_value) self._gromosXX_bin_dir = input_value else: raise FileNotFoundError(f"{str(input_value)} is not a valid directory.") - elif(isinstance(input_value, GromosXX)): + elif isinstance(input_value, GromosXX): self._gromosXX = input_value self._gromosXX_bin_dir = input_value.bin - elif(input_value is None): + elif input_value is None: self._gromosXX = None self._gromosXX_bin_dir = None else: raise ValueError(f"Could not parse input type: {str(type(input_value))} {str(input_value)}") @property - def gromosPP(self)->GromosPP: + def gromosPP(self) -> GromosPP: return self._gromosPP @gromosPP.setter - def gromosPP(self, input_value:Union[str, GromosPP]): - if(isinstance(input_value, str)): + def gromosPP(self, input_value: Union[str, GromosPP]): + if isinstance(input_value, str): # check if path to GromosPP binaries is a valid directory and if at least one is present - if(bash.directory_exists(input_value) and bash.command_exists(f"{input_value}/make_top")): + if bash.directory_exists(input_value) and bash.command_exists(f"{input_value}/make_top"): self._gromosPP = GromosPP(gromosPP_bin_dir=input_value) self._gromosPP_bin_dir = input_value else: raise FileNotFoundError(f"{str(input_value)} is not a valid directory.") - elif(isinstance(input_value, GromosPP)): + elif isinstance(input_value, GromosPP): self._gromosPP = input_value self._gromosPP_bin_dir = input_value.bin - elif(input_value is None): + elif input_value is None: self._gromosPP = None self._gromosPP_bin_dir = None else: raise ValueError("Could not parse input type: " + str(type(input_value)) + " " + str(input_value)) - """ Functions """ @@ -631,21 +732,40 @@ def gromosPP(self, input_value:Union[str, GromosPP]): """ System generation """ - def get_script_generation_command(self, var_name:str=None, var_prefixes:str ="")->str: - if(var_name is None): - var_name=var_prefixes + self.__class__.__name__.lower() - gen_cmd = "#Generate "+ self.__class__.__name__+ "\n" - gen_cmd += "from " + self.__module__ + " import "+ self.__class__.__name__+" as "+ self.__class__.__name__+"_obj"+ "\n" - gen_cmd += var_name+" = "+__class__.__name__+"_obj(work_folder=\""+self.work_folder+"\", system_name=\""+self.name+"\")\n" + def get_script_generation_command(self, var_name: str = None, var_prefixes: str = "") -> str: + if var_name is None: + var_name = var_prefixes + self.__class__.__name__.lower() + + gen_cmd = "#Generate " + self.__class__.__name__ + "\n" + gen_cmd += ( + "from " + + self.__module__ + + " import " + + self.__class__.__name__ + + " as " + + self.__class__.__name__ + + "_obj" + + "\n" + ) + gen_cmd += ( + var_name + + " = " + + __class__.__name__ + + '_obj(work_folder="' + + self.work_folder + + '", system_name="' + + self.name + + '")\n' + ) for arg, path in self.all_file_paths.items(): - gen_cmd+= str(var_name)+"."+str(arg)+" = \""+str(path)+"\"\n" - gen_cmd+="\n" + gen_cmd += str(var_name) + "." + str(arg) + ' = "' + str(path) + '"\n' + gen_cmd += "\n" return gen_cmd - def parse_attribute_files(self, file_mapping: Dict[str, str], readIn:bool=True, verbose:bool=False): + def parse_attribute_files(self, file_mapping: Dict[str, str], readIn: bool = True, verbose: bool = False): """ This function sets dynamically builds the output folder, the file objs of this class and checks their dependencies. @@ -662,73 +782,81 @@ def parse_attribute_files(self, file_mapping: Dict[str, str], readIn:bool=True, check_file_paths = [] ##Check if system folder is present - if (not os.path.exists(self._work_folder)): + if not os.path.exists(self._work_folder): bash.make_folder(self._work_folder) check_file_paths.append(self._work_folder) ## Check if file- paths are valid - all_files = {key:val for key, val in self.required_files.items()} + all_files = {key: val for key, val in self.required_files.items()} all_files.update(self.optional_files) [check_file_paths.append(x) for k, x in file_mapping.items() if (not x is None)] - if (len(check_file_paths) > 0): + if len(check_file_paths) > 0: bash.check_path_dependencies(check_file_paths, verbose=verbose) # SET Attribute-FILES for attribute_name, file_path in file_mapping.items(): - if(readIn and not file_path is None): - if (verbose): print("Parsing File: ", attribute_name) + if readIn and not file_path is None: + if verbose: + print("Parsing File: ", attribute_name) obj = all_files[attribute_name](file_path) - elif(attribute_name in self.required_files): - if (verbose): print("Generate Empty: ", attribute_name) - obj = all_files[attribute_name](None, _future_file = True) + elif attribute_name in self.required_files: + if verbose: + print("Generate Empty: ", attribute_name) + obj = all_files[attribute_name](None, _future_file=True) obj.path = file_path - if(not file_path is None): + if not file_path is None: self._future_promise = True self._future_promised_files.append(attribute_name) else: obj = None - setattr(self, "_"+attribute_name, obj) + setattr(self, "_" + attribute_name, obj) - #if read in of files - try to adapt the imd file necessaries + # if read in of files - try to adapt the imd file necessaries def _update_all_file_paths(self): for file_name in self._all_files_key: - if(hasattr(self, file_name) and not getattr(self, file_name) is None): - file_obj = getattr(self, file_name,) - if(file_obj._future_file): - if(self.verbose or True): warnings.warn("Did not change file path as its only promised " + str(file_obj.path)) + if hasattr(self, file_name) and not getattr(self, file_name) is None: + file_obj = getattr( + self, + file_name, + ) + if file_obj._future_file: + if self.verbose or True: + warnings.warn("Did not change file path as its only promised " + str(file_obj.path)) else: - file_obj.path = self._work_folder + "/" + self.name + "." + getattr(self, file_name)._gromos_file_ending + file_obj.path = ( + self._work_folder + "/" + self.name + "." + getattr(self, file_name)._gromos_file_ending + ) def rebase_files(self): - if(not os.path.exists(self.work_folder) and os.path.exists(os.path.dirname(self.work_folder))): + if not os.path.exists(self.work_folder) and os.path.exists(os.path.dirname(self.work_folder)): bash.make_folder(self.work_folder) self._update_all_file_paths() self.write_files() def _check_promises(self): - #misc - self._all_files_key = list(map(lambda x: "_"+x, self.required_files.keys())) - self._all_files_key.extend(list(map(lambda x: "_"+x, self.optional_files.keys()))) + # misc + self._all_files_key = list(map(lambda x: "_" + x, self.required_files.keys())) + self._all_files_key.extend(list(map(lambda x: "_" + x, self.optional_files.keys()))) for promised_file_key in self._future_promised_files: promised_file = getattr(self, promised_file_key) - if(os.path.exists(promised_file.path)): - if (self.verbose): + if os.path.exists(promised_file.path): + if self.verbose: print("READING FILE") setattr(self, "_" + promised_file_key, self._all_files[promised_file_key](promised_file.path)) self._future_promised_files.remove(promised_file_key) else: - warnings.warn("Promised file was not found: "+promised_file_key) - if(len(self._future_promised_files) == 0): + warnings.warn("Promised file was not found: " + promised_file_key) + if len(self._future_promised_files) == 0: self._future_promise = False def auto_convert(self): - #create topology + # create topology if self.Forcefield.name == "2016H66" or self.Forcefield.name == "54A7": # set parameters for make_top - out=self.work_folder+"/make_top.top" + out = self.work_folder + "/make_top.top" mtb_temp = self.Forcefield.mtb_path if hasattr(self.Forcefield, "mtb_orga_path"): mtb_temp += " " + self.Forcefield.mtb_orga_path @@ -739,25 +867,43 @@ def auto_convert(self): name = self.Forcefield.mol_name # make top if bash.command_exists(f"{self.gromosPP_bin_dir}/make_top"): - self.gromosPP.make_top(out_top_path=out, in_building_block_lib_path=mtb_temp, in_parameter_lib_path=ifp_temp, in_sequence=name) + self.gromosPP.make_top( + out_top_path=out, + in_building_block_lib_path=mtb_temp, + in_parameter_lib_path=ifp_temp, + in_sequence=name, + ) self.top = Top(in_value=out) else: - warnings.warn("could not find a gromosPP version. Please provide a valid version for Gromos auto system generation") - - elif self.Forcefield.name == "smirnoff" or self.Forcefield.name == "off" or self.Forcefield.name == "openforcefield": + warnings.warn( + "could not find a gromosPP version. Please provide a valid version for Gromos auto system generation" + ) + + elif ( + self.Forcefield.name == "smirnoff" + or self.Forcefield.name == "off" + or self.Forcefield.name == "openforcefield" + ): if not has_openff: - raise ImportError("Could not import smirnoff FF as openFF toolkit was missing! " - "Please install the package for this feature!") + raise ImportError( + "Could not import smirnoff FF as openFF toolkit was missing! " + "Please install the package for this feature!" + ) else: - self.top = openforcefield2gromos(Molecule.from_rdkit(self.mol), self.top, - forcefield=self.Forcefield).convert_return() + self.top = openforcefield2gromos( + Molecule.from_rdkit(self.mol), self.top, forcefield=self.Forcefield + ).convert_return() elif self.Forcefield.name == "serenityff" or self.Forcefield.name == "sff": if not has_openff: - raise ImportError("Could not import smirnoff FF as openFF toolkit was missing! " - "Please install the package for this feature!") + raise ImportError( + "Could not import smirnoff FF as openFF toolkit was missing! " + "Please install the package for this feature!" + ) else: self.serenityff = serenityff(mol=self.mol, forcefield=self.Forcefield, top=self.top) - self.serenityff.create_top(C12_input=self.Forcefield.C12_input, partial_charges=self.Forcefield.partial_charges) + self.serenityff.create_top( + C12_input=self.Forcefield.C12_input, partial_charges=self.Forcefield.partial_charges + ) self.serenityff.top.make_ordered() self.top = self.serenityff.top @@ -767,19 +913,26 @@ def auto_convert(self): def rdkit2GromosName(self) -> str: raise NotImplementedError("please find your own way to get the Gromos Name for your molecule.") - def prepare_for_simulation(self, not_ligand_residues:List[str]=[]): + def prepare_for_simulation(self, not_ligand_residues: List[str] = []): self.adapt_imd(not_ligand_residues=not_ligand_residues) - def adapt_imd(self, not_ligand_residues:List[str]=[]): + def adapt_imd(self, not_ligand_residues: List[str] = []): # Get residues - if(self.cnf._future_file and self.residue_list is None + if ( + self.cnf._future_file + and self.residue_list is None and self.solute_info is None and self.protein_info is None - and self.non_ligand_info is None): - raise ValueError("The residue_list, solute_info, protein_info adn non_ligand_info are required for automatic imd-adaptation.") + and self.non_ligand_info is None + ): + raise ValueError( + "The residue_list, solute_info, protein_info adn non_ligand_info are required for automatic imd-adaptation." + ) else: - if(not self.cnf._future_file): - cres, lig, prot, nonLig, solvent = self.cnf.get_system_information(not_ligand_residues=not_ligand_residues) + if not self.cnf._future_file: + cres, lig, prot, nonLig, solvent = self.cnf.get_system_information( + not_ligand_residues=not_ligand_residues + ) self.residue_list = cres self.solute_info = lig self.protein_info = prot @@ -787,104 +940,114 @@ def adapt_imd(self, not_ligand_residues:List[str]=[]): self.solvent_info = solvent ##System self.imd.SYSTEM.NPM = 1 - self.imd.SYSTEM.NSM = len(self.residue_list ["SOLV"]) if("SOLV" in self.residue_list ) else 0 + self.imd.SYSTEM.NSM = len(self.residue_list["SOLV"]) if ("SOLV" in self.residue_list) else 0 - #boundary condition: + # boundary condition: from pygromos.files.blocks.coord_blocks import Pbc + ##vacuum if no box or GENBOX-pbc == Vacuum - if (not self.cnf._future_file and (not hasattr(self.cnf, "GENBOX") or self.cnf.GENBOX.pbc == Pbc.vacuum)): + if not self.cnf._future_file and (not hasattr(self.cnf, "GENBOX") or self.cnf.GENBOX.pbc == Pbc.vacuum): self.imd.BOUNDCOND.NTB = Pbc.vacuum.value - elif(not self.cnf._future_file and (not hasattr(self.cnf, "GENBOX") or self.cnf.GENBOX.pbc == Pbc.rectangular)): + elif not self.cnf._future_file and (not hasattr(self.cnf, "GENBOX") or self.cnf.GENBOX.pbc == Pbc.rectangular): self.imd.BOUNDCOND.NTB = Pbc.rectangular.value self.imd.BOUNDCOND.NDFMIN = 3 - ##Energy and Force Group energy_groups = {} - if(self._single_energy_group): - energy_groups = {self.solute_info.number_of_atoms + self.protein_info.number_of_atoms + self.non_ligand_info.number_of_atoms + self.solvent_info.number_of_atoms:1} + if self._single_energy_group: + energy_groups = { + self.solute_info.number_of_atoms + + self.protein_info.number_of_atoms + + self.non_ligand_info.number_of_atoms + + self.solvent_info.number_of_atoms: 1 + } else: - #solute - if(self.solute_info.number_of_atoms>0): + # solute + if self.solute_info.number_of_atoms > 0: energy_groups.update({self.solute_info.positions[0]: self.solute_info.number_of_atoms}) - #protein - if (self.protein_info.number_of_atoms > 0): + # protein + if self.protein_info.number_of_atoms > 0: energy_groups.update({self.protein_info.start_position: self.protein_info.number_of_atoms}) - #ligand - if (self.non_ligand_info.number_of_atoms > 0): + # ligand + if self.non_ligand_info.number_of_atoms > 0: solv_add = self.non_ligand_info.number_of_atoms else: solv_add = 0 - #solvent - if(self.solvent_info.number_of_atoms > 0): - max_key = max(energy_groups)+1 if(len(energy_groups)>0) else 1 - energy_groups.update({max_key: self.solvent_info.number_of_atoms+solv_add}) + # solvent + if self.solvent_info.number_of_atoms > 0: + max_key = max(energy_groups) + 1 if (len(energy_groups) > 0) else 1 + energy_groups.update({max_key: self.solvent_info.number_of_atoms + solv_add}) - #sort all entries in list + # sort all entries in list last_atom_count = 0 sorted_energy_groups = {} - for ind,key in enumerate(sorted(energy_groups)): - value = energy_groups[key]+last_atom_count - sorted_energy_groups.update({1+ind : value}) - last_atom_count=value + for ind, key in enumerate(sorted(energy_groups)): + value = energy_groups[key] + last_atom_count + sorted_energy_groups.update({1 + ind: value}) + last_atom_count = value - #adapt energy groups in IMD with sorted list of energy groups created above + # adapt energy groups in IMD with sorted list of energy groups created above self.imd.FORCE.adapt_energy_groups(energy_groups=sorted_energy_groups) ##Multibath: - if (hasattr(self.imd, "MULTIBATH") and not getattr(self.imd, "MULTIBATH") is None): + if hasattr(self.imd, "MULTIBATH") and not getattr(self.imd, "MULTIBATH") is None: last_atoms_baths = {} - if(self._single_multibath): - sorted_last_atoms_baths = { self.solute_info.number_of_atoms + self.protein_info.number_of_atoms + self.non_ligand_info.number_of_atoms + self.solvent_info.number_of_atoms:1} + if self._single_multibath: + sorted_last_atoms_baths = { + self.solute_info.number_of_atoms + + self.protein_info.number_of_atoms + + self.non_ligand_info.number_of_atoms + + self.solvent_info.number_of_atoms: 1 + } else: - if(self.solute_info.number_of_atoms>0): + if self.solute_info.number_of_atoms > 0: last_atoms_baths.update({self.solute_info.positions[0]: self.solute_info.number_of_atoms}) - if (self.protein_info.number_of_atoms > 0): + if self.protein_info.number_of_atoms > 0: last_atoms_baths.update({self.protein_info.start_position: self.protein_info.number_of_atoms}) - if (self.non_ligand_info.number_of_atoms > 0): + if self.non_ligand_info.number_of_atoms > 0: solv_add = self.non_ligand_info.number_of_atoms - #raise Exception("The imd adaptation for nonLigand res and multibath was not written yet!") + # raise Exception("The imd adaptation for nonLigand res and multibath was not written yet!") # TODO: Do something for non-Ligands better in future else: solv_add = 0 - if(self.solvent_info.number_of_atoms > 0): - max_key = max(last_atoms_baths)+1 if(len(last_atoms_baths)>0) else 1 - last_atoms_baths.update({max_key: self.solvent_info.number_of_atoms+solv_add}) + if self.solvent_info.number_of_atoms > 0: + max_key = max(last_atoms_baths) + 1 if (len(last_atoms_baths) > 0) else 1 + last_atoms_baths.update({max_key: self.solvent_info.number_of_atoms + solv_add}) last_atom_count = 0 sorted_last_atoms_baths = {} - for ind,key in enumerate(sorted(last_atoms_baths)): - value = last_atoms_baths[key]+last_atom_count - sorted_last_atoms_baths.update({value:1+ind}) - last_atom_count=value - + for ind, key in enumerate(sorted(last_atoms_baths)): + value = last_atoms_baths[key] + last_atom_count + sorted_last_atoms_baths.update({value: 1 + ind}) + last_atom_count = value + self.imd.MULTIBATH.adapt_multibath(last_atoms_bath=sorted_last_atoms_baths) ff_name = self.Forcefield.name if ff_name == "openforcefield" or ff_name == "smirnoff" or ff_name == "off": - #adjust harmonic forces - if (hasattr(self.imd, "COVALENTFORM") and not getattr(self.imd, "COVALENTFORM") is None): + # adjust harmonic forces + if hasattr(self.imd, "COVALENTFORM") and not getattr(self.imd, "COVALENTFORM") is None: if self.verbose: print("Please make sure to use harmonic forces for simulations with OpenForceField torsions") else: - setattr(self.imd,"COVALENTFORM", imd_blocks.COVALENTFORM(NTBBH=1, NTBAH=1, NTBDN=0)) - #adjust amberscale for LJ forces - if (hasattr(self.imd, "AMBER") and not getattr(self.imd, "AMBER") is None): + setattr(self.imd, "COVALENTFORM", imd_blocks.COVALENTFORM(NTBBH=1, NTBAH=1, NTBDN=0)) + # adjust amberscale for LJ forces + if hasattr(self.imd, "AMBER") and not getattr(self.imd, "AMBER") is None: if self.verbose: print("Please make sure to use amber LJ forces for simulations with OpenForceField LJ parameters") else: - setattr(self.imd,"AMBER", imd_blocks.AMBER(AMBER=1, AMBSCAL=1.2)) + setattr(self.imd, "AMBER", imd_blocks.AMBER(AMBER=1, AMBSCAL=1.2)) - def generate_posres(self, residues:list=[], keep_residues:bool=True, verbose:bool=False): + def generate_posres(self, residues: list = [], keep_residues: bool = True, verbose: bool = False): self.posres = self.cnf.gen_possrespec(residues=residues, keep_residues=keep_residues, verbose=verbose) self.refpos = self.cnf.gen_refpos() - """ IO - Files: """ - def read_files(self, verbose:bool=False): + + def read_files(self, verbose: bool = False): for file_name in self.required_files: try: getattr(self, file_name).read_file() @@ -895,39 +1058,56 @@ def read_files(self, verbose:bool=False): try: getattr(self, file_name).read_file() except: - if (verbose): + if verbose: warnings.warn("did not find the optional " + file_name + " found") - - def write_files(self, cnf:bool=False, imd:bool=False, - top: bool = False, ptp:bool=False, - disres:bool=False, posres: bool = False, refpos: bool = False, - qmmm:bool=False, mol: bool = False, - all:bool=True, - verbose:bool=False): - if(all): + def write_files( + self, + cnf: bool = False, + imd: bool = False, + top: bool = False, + ptp: bool = False, + disres: bool = False, + posres: bool = False, + refpos: bool = False, + qmmm: bool = False, + mol: bool = False, + all: bool = True, + verbose: bool = False, + ): + if all: control = {k.replace("_", ""): all for k in self._all_files_key} else: - control = {"top": top, "imd": imd, "cnf": cnf, "ptp":ptp, "disres":disres, "posres":posres, "refpos":refpos, "qmmm":qmmm} + control = { + "top": top, + "imd": imd, + "cnf": cnf, + "ptp": ptp, + "disres": disres, + "posres": posres, + "refpos": refpos, + "qmmm": qmmm, + } for file_name in control: - if (control[file_name] and hasattr(self, file_name) and (not getattr(self, file_name) is None)): + if control[file_name] and hasattr(self, file_name) and (not getattr(self, file_name) is None): file_obj = getattr(self, file_name) - if(file_obj.path is None): - print("File "+str(file_name)+" is empty , can not be written!") - elif(file_obj._future_file): - print("File " + str(file_name) +" is promised , can not be written: " + str(file_obj.path)) + if file_obj.path is None: + print("File " + str(file_name) + " is empty , can not be written!") + elif file_obj._future_file: + print("File " + str(file_name) + " is promised , can not be written: " + str(file_obj.path)) else: - if(verbose): print("Write out: " + str(file_name) +"\t" + file_obj.path) + if verbose: + print("Write out: " + str(file_name) + "\t" + file_obj.path) file_obj.write(file_obj.path) else: - if(file_name in self.required_files): + if file_name in self.required_files: warnings.warn("did not find the required " + file_name + " found") - elif(verbose): + elif verbose: warnings.warn("did not find the required " + file_name + " found") if mol: - print(Chem.MolToMolBlock(self.mol), file=open(self._work_folder + "/" + self.name + ".mol", 'w+')) + print(Chem.MolToMolBlock(self.mol), file=open(self._work_folder + "/" + self.name + ".mol", "w+")) def get_file_paths(self) -> Dict[str, str]: """ @@ -948,33 +1128,41 @@ def rdkitImport(self, inputMol: Chem.rdchem.Mol): def rdkit2Gromos(self): # generate top - self.top.add_block(blocktitle="TITLE", content=[ - "topology generated with PyGromos from RDKit molecule: " + str(Chem.MolToSmiles(self.mol)) + " " + str( - self.name)], verbose=True) + self.top.add_block( + blocktitle="TITLE", + content=[ + "topology generated with PyGromos from RDKit molecule: " + + str(Chem.MolToSmiles(self.mol)) + + " " + + str(self.name) + ], + verbose=True, + ) self.top.add_block(blocktitle="PHYSICALCONSTANTS", content=[""], verbose=True) self.top.add_block(blocktitle="TOPVERSION", content=[["2.0"]]) """ Serialize """ - def save(self, path: Union[str, io.FileIO] = None, safe:bool=True) -> str: + + def save(self, path: Union[str, io.FileIO] = None, safe: bool = True) -> str: """ This method stores the Class as binary obj to a given path or fileBuffer. """ safe_skip = False - if (isinstance(path, str)): - if (os.path.exists(path) and safe): + if isinstance(path, str): + if os.path.exists(path) and safe: warnings.warn("FOUND ALREADY A FILE! SKIPPING!") safe_skip = True else: bufferdWriter = open(path, "wb") - elif (isinstance(path, io.BufferedWriter)): + elif isinstance(path, io.BufferedWriter): bufferdWriter = path path = bufferdWriter.name else: raise IOError("Please give as parameter a path:str or a File Buffer. To " + str(self.__class__) + ".save") - if(not safe_skip): + if not safe_skip: pickle.dump(obj=self, file=bufferdWriter) bufferdWriter.close() self.checkpoint_path = path @@ -985,9 +1173,9 @@ def load(cls, path: Union[str, io.FileIO] = None) -> object: """ This method stores the Class as binary obj to a given path or fileBuffer. """ - if (isinstance(path, str)): + if isinstance(path, str): bufferedReader = open(path, "rb") - elif (isinstance(path, io.BufferedReader)): + elif isinstance(path, io.BufferedReader): bufferedReader = path else: raise IOError("Please give as parameter a path:str or a File Buffer.") @@ -995,16 +1183,22 @@ def load(cls, path: Union[str, io.FileIO] = None) -> object: obj = pickle.load(file=bufferedReader) bufferedReader.close() - if(hasattr(obj, "cnf") and hasattr(obj.cnf, "POSITION")): - obj.residue_list, obj.solute_info, obj.protein_info, obj.non_ligand_info, obj.solvent_info = obj._cnf.get_system_information() + if hasattr(obj, "cnf") and hasattr(obj.cnf, "POSITION"): + ( + obj.residue_list, + obj.solute_info, + obj.protein_info, + obj.non_ligand_info, + obj.solvent_info, + ) = obj._cnf.get_system_information() obj.checkpoint_path = path return obj - """ super privates - don't even read! """ - def __SystemConstructionAttributeFinder(self, func:callable) -> callable: + + def __SystemConstructionAttributeFinder(self, func: callable) -> callable: """ ** DECORATOR ** @@ -1024,20 +1218,20 @@ def __SystemConstructionAttributeFinder(self, func:callable) -> callable: @functools.wraps(func) def findGromosSystemAttributes(*args, **kwargs): - #print(func.__name__, args, kwargs) + # print(func.__name__, args, kwargs) # collect input parameters present in system/ replace them with tmp_files = [] for k in inspect.signature(func).parameters: attr_key = k.replace("in_", "").replace("_path", "") - #print(attr_key) - if ("in" in k and "path" in k and attr_key in dir(self)): + # print(attr_key) + if "in" in k and "path" in k and attr_key in dir(self): grom_obj = getattr(self, attr_key) - if(isinstance(grom_obj, str)): + if isinstance(grom_obj, str): kwargs.update({k: grom_obj}) - elif(hasattr(grom_obj, "path") and grom_obj.path is None): + elif hasattr(grom_obj, "path") and grom_obj.path is None: tmp_file_path = self.work_folder + "/tmp_in_file." + grom_obj._gromos_file_ending grom_obj.write(tmp_file_path) kwargs.update({k: tmp_file_path}) @@ -1059,7 +1253,7 @@ def findGromosSystemAttributes(*args, **kwargs): red_params = [] for key, par in sig.parameters.items(): attr_key = key.replace("in_", "").replace("_path", "") - if ("in" in key and "path" in key and attr_key in dir(self)): + if "in" in key and "path" in key and attr_key in dir(self): continue else: red_params.append(par) @@ -1068,7 +1262,7 @@ def findGromosSystemAttributes(*args, **kwargs): return findGromosSystemAttributes - def __SystemConstructionUpdater(self, func:callable) -> callable: + def __SystemConstructionUpdater(self, func: callable) -> callable: """ ** DECORATOR ** This decorator trys to find output parameters of the function in the gromossystem and will automatically update the state of those attributes! @@ -1087,12 +1281,12 @@ def __SystemConstructionUpdater(self, func:callable) -> callable: @functools.wraps(func) def updateGromosSystem(*args, **kwargs): - #rint(func.__name__, args, kwargs) + # rint(func.__name__, args, kwargs) # collect out_paths update_dict = {} for k in inspect.signature(func).parameters: - if ("out" in k and "path" in k): + if "out" in k and "path" in k: attr_key = k.replace("out_", "").replace("_path", "") kwargs.update({k: self.work_folder + "/tmp_out_file." + attr_key}) update_dict.update({k: attr_key}) @@ -1112,7 +1306,7 @@ def updateGromosSystem(*args, **kwargs): sig = inspect.signature(func) red_params = [] for key, par in sig.parameters.items(): - if ("out" in key and "path" in key): + if "out" in key and "path" in key: continue else: red_params.append(par) @@ -1139,56 +1333,57 @@ def __ionDecorator(self, func: callable) -> callable: """ @functools.wraps(func) - def generate_ion_top(in_building_block_lib_path=Gromos54A7.mtb, - in_parameter_lib_path=Gromos54A7.ifp, - *args, **kwargs): + def generate_ion_top( + in_building_block_lib_path=Gromos54A7.mtb, in_parameter_lib_path=Gromos54A7.ifp, *args, **kwargs + ): # execute function r = func(*args, **kwargs) top_cl = self.work_folder + "/aux_tmp.top" sequence = "" - if("negative" in kwargs): - nIons, ion = kwargs['negative'] - sequence += (ion+" ")*nIons - if("positive" in kwargs): - nIons, ion = kwargs['positive'] - sequence += (ion+" ")*nIons - - self._gromosPP.make_top(in_building_block_lib_path=in_building_block_lib_path, - in_parameter_lib_path=in_parameter_lib_path, - in_sequence=sequence, - in_solvent="H2O", - out_top_path=top_cl) + if "negative" in kwargs: + nIons, ion = kwargs["negative"] + sequence += (ion + " ") * nIons + if "positive" in kwargs: + nIons, ion = kwargs["positive"] + sequence += (ion + " ") * nIons + + self._gromosPP.make_top( + in_building_block_lib_path=in_building_block_lib_path, + in_parameter_lib_path=in_parameter_lib_path, + in_sequence=sequence, + in_solvent="H2O", + out_top_path=top_cl, + ) self.top += Top(top_cl) bash.remove_file(top_cl) return r - # Override signature for usage in jupyter env or IDE sig = inspect.signature(func) sig2 = inspect.signature(self._gromosPP.make_top) - red_params = [sig2.parameters['in_building_block_lib_path']] - red_params.append(sig2.parameters['in_parameter_lib_path']) + red_params = [sig2.parameters["in_building_block_lib_path"]] + red_params.append(sig2.parameters["in_parameter_lib_path"]) red_params.extend(list(sig.parameters.values())) - red_sig = sig.replace(parameters=red_params) generate_ion_top.__signature__ = red_sig - return generate_ion_top - def __bind_gromosPPFuncs(self): - if(not self._gromosPP is None): + if not self._gromosPP is None: func = [k for k in dir(self._gromosPP) if (not k.startswith("_") and k != "bin")] - v = {f: self.__SystemConstructionUpdater(self.__SystemConstructionAttributeFinder(getattr(self._gromosPP, f))) - for f in func} - #this is clunky and needs to be removed in future - rewrap = self.__ionDecorator(v['ion']) + v = { + f: self.__SystemConstructionUpdater( + self.__SystemConstructionAttributeFinder(getattr(self._gromosPP, f)) + ) + for f in func + } + # this is clunky and needs to be removed in future + rewrap = self.__ionDecorator(v["ion"]) v.update({"ion": rewrap}) self.__dict__.update(v) - diff --git a/pygromos/files/otherfiles/new_repdat.py b/pygromos/files/otherfiles/new_repdat.py index 8704d52c..6d9cf64f 100644 --- a/pygromos/files/otherfiles/new_repdat.py +++ b/pygromos/files/otherfiles/new_repdat.py @@ -11,41 +11,43 @@ from pygromos.files.blocks import replica_exchange_blocks as blocks -#forward declaration like - for typing - ugly - TODO +# forward declaration like - for typing - ugly - TODO class Repdat: pass + class Repdat(pd.DataFrame): # """Replica exchange statistic file - This class is a representation for all transition information during a replica exchange run. it adds some useful functionality. + This class is a representation for all transition information during a replica exchange run. it adds some useful functionality. """ + _gromos_file_ending = "restat" - #pandas specific parameters: + # pandas specific parameters: @property def _constructor(self): return Repdat - _metadata = ['added_property'] + _metadata = ["added_property"] added_property = 1 # This will be passed to copies - #gromos fun + # gromos fun SYSTEM: blocks.repex_system DATA: pd.DataFrame - #transition_traces[replica][["trials", "positions". "state_pot"]] - transition_traces:Dict[int, Dict[str,List[float]]] = None + # transition_traces[replica][["trials", "positions". "state_pot"]] + transition_traces: Dict[int, Dict[str, List[float]]] = None - #count_state_per_position[replicaposition][["tot_nup", "tot_ndown", "states_index", "dt", "dt_nup", "dt_ndown"]] - count_state_per_position:Dict[int, Dict[str, Union[List or float]]] = None + # count_state_per_position[replicaposition][["tot_nup", "tot_ndown", "states_index", "dt", "dt_nup", "dt_ndown"]] + count_state_per_position: Dict[int, Dict[str, Union[List or float]]] = None - #count_state_per_position[replica] - replica_round_trips:Dict[int,int] = None + # count_state_per_position[replica] + replica_round_trips: Dict[int, int] = None def __init__(self, input_path: str): - """ Repdat_Constructor + """Repdat_Constructor Parameters ---------- @@ -56,14 +58,12 @@ def __init__(self, input_path: str): if type(input_path) is str: system, df = parser.read_repdat(input_path, Vj_header=True) self.system = system - self.DATA = df #future data field a pandas frame! + self.DATA = df # future data field a pandas frame! self.path = input_path else: raise NotImplementedError("Not correct yet!") - - - def _clean_replica_round_trips(self, replica_round_trips:Dict[int,int])->Dict[int,int]: + def _clean_replica_round_trips(self, replica_round_trips: Dict[int, int]) -> Dict[int, int]: """_clean_replica_round_trips - privat This function cleans up so that the minimal rountrip number in a roundtrip dict is 0 @@ -80,16 +80,16 @@ def _clean_replica_round_trips(self, replica_round_trips:Dict[int,int])->Dict[in """ - #clean up indices that are -1 + # clean up indices that are -1 clean_replica_round_trips = {} - for key,item in replica_round_trips.items(): - if(item!=-1): - clean_replica_round_trips.update({key:item}) + for key, item in replica_round_trips.items(): + if item != -1: + clean_replica_round_trips.update({key: item}) else: - clean_replica_round_trips.update({key:0}) + clean_replica_round_trips.update({key: 0}) return clean_replica_round_trips - def _caculate_transition_traces(self)->None: + def _caculate_transition_traces(self) -> None: """ TODO: refactor code! ..autofunction: _caculate_transition_traces @@ -105,27 +105,31 @@ def _caculate_transition_traces(self)->None: replicas = len(self.system.s) # follow transitions of one state - transition_dict = {x: x for x in range(1, replicas + 1)} # keeps track of unique id and current replica position. + transition_dict = { + x: x for x in range(1, replicas + 1) + } # keeps track of unique id and current replica position. tmp_dict = {x: x for x in range(1, replicas + 1)} - transition_result_dict = {x: {"trial": [], "position": [], "state_pot": []} for x in range(1,replicas + 1)} # init transition dicts following one replica with inital start + transition_result_dict = { + x: {"trial": [], "position": [], "state_pot": []} for x in range(1, replicas + 1) + } # init transition dicts following one replica with inital start # go through repda and count tmp_run = 1 for index, row in self.DATA_NEW.iterrows(): - if(tmp_run != row.run): #new trial + if tmp_run != row.run: # new trial transition_dict = tmp_dict tmp_dict = {x: x for x in range(1, replicas + 1)} tmp_run = row.run # Exchange Replica - replica = int(transition_dict[int(row.ID)]) #get the replica unique id + replica = int(transition_dict[int(row.ID)]) # get the replica unique id ##record Exchange - if (row.s == 1): # only hit when exchange and not partner already exchangeds + if row.s == 1: # only hit when exchange and not partner already exchangeds # new_pos transition_result_dict[replica]["trial"].append(int(row.run)) transition_result_dict[replica]["position"].append(int(row.partner)) transition_result_dict[replica]["state_pot"].append(row.state_potentials) - #exchange reps + # exchange reps tmp_dict[int(row.partner)] = replica else: @@ -134,16 +138,18 @@ def _caculate_transition_traces(self)->None: transition_result_dict[replica]["state_pot"].append(row.state_potentials) tmp_dict[int(row.ID)] = replica - #if (replica == 2 and row.run < 10): + # if (replica == 2 and row.run < 10): # print("trial ", row.run, "ID ", row.ID, "partner ", row.partner) # print("replica: ", transition_dict[row.ID], "vs.", transition_dict[row.partner]) # print("transd", transition_result_dict[2]["position"]) traces = {x: pd.DataFrame(transition_result_dict[x]) for x in transition_result_dict} [df.insert(0, "replicaID", replicaID) for replicaID, df in traces.items()] - self.transition_traces = pd.concat(traces) + self.transition_traces = pd.concat(traces) - def _calculate_ndowns_nups_for_each_state(self, time_stride:int = -1, min_state_potential_treshold:float=None, verbose:bool=False): + def _calculate_ndowns_nups_for_each_state( + self, time_stride: int = -1, min_state_potential_treshold: float = None, verbose: bool = False + ): """_calculate_ndowns_nups_for_each_state calculates the visit counts for each replicaID position (Temperature or s_value). @@ -173,38 +179,47 @@ def _calculate_ndowns_nups_for_each_state(self, time_stride:int = -1, min_state_ num_states = len(self.system.state_eir) num_replica = len(self.system.s) - if (time_stride < 1): - time_stride = 1 #arbitrary window size value, that seems reasonable! len(replica_traces[list(replica_traces.keys())[0]]["trial"]) * 0.01 + if time_stride < 1: + time_stride = 1 # arbitrary window size value, that seems reasonable! len(replica_traces[list(replica_traces.keys())[0]]["trial"]) * 0.01 - extreme_positions = (1, num_replica) #gives the extreme values of the replicaID dist - replica_extreme_position_memory = {replica: -1 for replica in range(1, num_replica + 1)} #which replicaID visited which extreme? - replica_extreme_position_memory.update({1: extreme_positions[0], num_replica: extreme_positions[1]}) #init pos1 and last one + extreme_positions = (1, num_replica) # gives the extreme values of the replicaID dist + replica_extreme_position_memory = { + replica: -1 for replica in range(1, num_replica + 1) + } # which replicaID visited which extreme? + replica_extreme_position_memory.update( + {1: extreme_positions[0], num_replica: extreme_positions[1]} + ) # init pos1 and last one # result vars - #for easier keeping track of state indices + # for easier keeping track of state indices state_index = {key: key for key in range(num_states)} - if(min_state_potential_treshold!=None): #add an undef state if multiple residues are below threshold. - state_index.update({"undefined":num_states}) - num_states+=1 - - count_state_perpos = {positionID: {"tot_nup": [0 for state in state_index], - "tot_ndown": [0 for state in state_index], - "dt": time_stride, - "pot_tresh":min_state_potential_treshold, - "states_index": state_index, - "dt_nup": [[0 for state in state_index]], - "dt_ndown": [[0 for state in state_index]]} - for positionID in range(1, num_replica + 1)} - - - if verbose: print("general: ", extreme_positions) - if verbose: print("time_window_size: ", time_stride) - #if verbose: print("INITIAL") - #if verbose: print("Initial count_per_repPos\n", count_state_per_position) - #if verbose: print("Initial current_extremePos_replica\n", replica_extreme_position_memory) + if min_state_potential_treshold != None: # add an undef state if multiple residues are below threshold. + state_index.update({"undefined": num_states}) + num_states += 1 + + count_state_perpos = { + positionID: { + "tot_nup": [0 for state in state_index], + "tot_ndown": [0 for state in state_index], + "dt": time_stride, + "pot_tresh": min_state_potential_treshold, + "states_index": state_index, + "dt_nup": [[0 for state in state_index]], + "dt_ndown": [[0 for state in state_index]], + } + for positionID in range(1, num_replica + 1) + } + + if verbose: + print("general: ", extreme_positions) + if verbose: + print("time_window_size: ", time_stride) + # if verbose: print("INITIAL") + # if verbose: print("Initial count_per_repPos\n", count_state_per_position) + # if verbose: print("Initial current_extremePos_replica\n", replica_extreme_position_memory) # as side product easily the round trips can be calculated! - replica_round_trips = {replica: -1 for replica in range(1, num_replica+1)} + replica_round_trips = {replica: -1 for replica in range(1, num_replica + 1)} replica_round_trips[1] = 0 replica_round_trips[num_replica] = 0 @@ -212,43 +227,59 @@ def _calculate_ndowns_nups_for_each_state(self, time_stride:int = -1, min_state_ count_state_perpos[position]["dt_ndown"].append([0 for state in state_index]) count_state_perpos[position]["dt_nup"].append([0 for state in state_index]) - if (position in extreme_positions and replica_extreme_position_memory[replicaID] != position): + if position in extreme_positions and replica_extreme_position_memory[replicaID] != position: replica_extreme_position_memory.update({replicaID: position}) replica_round_trips[replicaID] += 1 - #This replicaID has already seen an extreme pos - if (replica_extreme_position_memory[replicaID] in extreme_positions): - #who is the active state? - if(min_state_potential_treshold!=None): # NEW shall no other state be in an undersampling situation? - undersampling_state_energies = [float(val) for val in list(pot_energies.values()) if (float(val) < min_state_potential_treshold)] - if(1==len(undersampling_state_energies)): #clean active states - only one state at a time underSampling + # This replicaID has already seen an extreme pos + if replica_extreme_position_memory[replicaID] in extreme_positions: + # who is the active state? + if min_state_potential_treshold != None: # NEW shall no other state be in an undersampling situation? + undersampling_state_energies = [ + float(val) for val in list(pot_energies.values()) if (float(val) < min_state_potential_treshold) + ] + if 1 == len( + undersampling_state_energies + ): # clean active states - only one state at a time underSampling active_state = undersampling_state_energies.index(min(undersampling_state_energies)) - else: #no clear state presen skip + else: # no clear state presen skip active_state = state_index["undefined"] else: - undersampling_state_energies = [float(val) for val in list(pot_energies.values())] # if(float(val) < 200)] + undersampling_state_energies = [ + float(val) for val in list(pot_energies.values()) + ] # if(float(val) < 200)] active_state = undersampling_state_energies.index(min(undersampling_state_energies)) # determine if replicaID comes from top or bottom and add +1 to stat - if (replica_extreme_position_memory[replicaID] == extreme_positions[0]): #coming from top + if replica_extreme_position_memory[replicaID] == extreme_positions[0]: # coming from top count_state_perpos[position]["tot_ndown"][active_state] += 1 count_state_perpos[position]["dt_ndown"][-1][active_state] += 1 - elif(replica_extreme_position_memory[replicaID] == extreme_positions[1]): #coming_from bottom + elif replica_extreme_position_memory[replicaID] == extreme_positions[1]: # coming_from bottom count_state_perpos[position]["tot_nup"][active_state] += 1 count_state_perpos[position]["dt_nup"][-1][active_state] += 1 - else: # NEW has never seen any thing + else: # NEW has never seen any thing raise ValueError("A replicaID has never seen a extreme position should not reach this code!") else: continue - if verbose: print("\nFINAL") - if verbose: print("Final extreme_positions", replica_extreme_position_memory) - if verbose: print("Final position counts totup/totdown: ", - [(count_state_perpos[pos]["tot_nup"], count_state_perpos[pos]["tot_ndown"]) for pos in count_state_perpos]) - if verbose: print("Final positoin counts keys", count_state_perpos[1].keys()) - if verbose: print("counted rountrips per replicaID!: ", replica_round_trips) - - #store trajs in pd.dataframes. + if verbose: + print("\nFINAL") + if verbose: + print("Final extreme_positions", replica_extreme_position_memory) + if verbose: + print( + "Final position counts totup/totdown: ", + [ + (count_state_perpos[pos]["tot_nup"], count_state_perpos[pos]["tot_ndown"]) + for pos in count_state_perpos + ], + ) + if verbose: + print("Final positoin counts keys", count_state_perpos[1].keys()) + if verbose: + print("counted rountrips per replicaID!: ", replica_round_trips) + + # store trajs in pd.dataframes. tmp_counts = self._clean_replica_round_trips(replica_round_trips) for x, data in tmp_counts.items(): column_names = ["state_" + str(data["states_index"][x]) for x in sorted(data["states_index"])] @@ -261,7 +292,6 @@ def _calculate_ndowns_nups_for_each_state(self, time_stride:int = -1, min_state_ tmp.columns = column_names data["dt_ndown"] = tmp - self.count_state_per_position = count_state_perpos self.replica_round_trips = tmp_counts @@ -278,27 +308,35 @@ def _calculate_replica_roundtrips(self): num_states = len(self.system.state_eir) num_replica = len(self.system.s) - extreme_positions = (1, num_replica) #gives the extreme values of the replica dist - replica_extreme_position_memory = {replica: -1 for replica in range(1, num_replica + 1)} #which replica visited which extreme? - replica_extreme_position_memory.update({1: extreme_positions[0], num_replica: extreme_positions[1]}) #init pos1 and last one + extreme_positions = (1, num_replica) # gives the extreme values of the replica dist + replica_extreme_position_memory = { + replica: -1 for replica in range(1, num_replica + 1) + } # which replica visited which extreme? + replica_extreme_position_memory.update( + {1: extreme_positions[0], num_replica: extreme_positions[1]} + ) # init pos1 and last one # as side product easily the round trips can be calculated! - replica_round_trips = {replica: -1 for replica in range(1, num_replica+1)} + replica_round_trips = {replica: -1 for replica in range(1, num_replica + 1)} replica_round_trips[1] = 0 replica_round_trips[num_replica] = 0 - #only go over_extreme postitions. - extreme_position_trace = replica_traces.loc[replica_traces.position.isin(extreme_positions)].sort_values("trial") - for index, (replicaID, trial, position, pot_energies) in extreme_position_trace.sort_values("trial").iterrows():# go through each replica trace + # only go over_extreme postitions. + extreme_position_trace = replica_traces.loc[replica_traces.position.isin(extreme_positions)].sort_values( + "trial" + ) + for index, (replicaID, trial, position, pot_energies) in extreme_position_trace.sort_values( + "trial" + ).iterrows(): # go through each replica trace # print(trial, position, pot_energies) - if (position in extreme_positions and replica_extreme_position_memory[replicaID] != position): + if position in extreme_positions and replica_extreme_position_memory[replicaID] != position: replica_extreme_position_memory.update({replicaID: position}) replica_round_trips[replicaID] += 1 else: continue self.replica_round_trips = self._clean_replica_round_trips(replica_round_trips) - def append(self, repdat:(List[Repdat] or Repdat)): + def append(self, repdat: (List[Repdat] or Repdat)): """append This function concatenates two repdat files into the executing obj. @@ -313,35 +351,33 @@ def append(self, repdat:(List[Repdat] or Repdat)): None """ - #if(self.system != repdat.system): + # if(self.system != repdat.system): # raise ValueError("The two repdats seem not to come from the same simulation, as the system settings are different!") - if(not isinstance(repdat, List)): + if not isinstance(repdat, List): repdat = [repdat] self.DATA_NEW = pd.concat([self.DATA_NEW, *map(lambda x: x.data2, repdat)], ignore_index=True) - self.DATA_NEW .run = pd.Series(map(lambda i: 1 + int(i) // len(self.system.s), self.DATA_NEW.index)) - + self.DATA_NEW.run = pd.Series(map(lambda i: 1 + int(i) // len(self.system.s), self.DATA_NEW.index)) def clean_file_runs(self): """clean_file - DEAPRECEATED - ABOUT TO BE REMOVED! + DEAPRECEATED - ABOUT TO BE REMOVED! - Updates the run numbers to be continous sequential. (for example needed for concatenation) + Updates the run numbers to be continous sequential. (for example needed for concatenation) """ tmp_run = 0 offset = 0 for line in self.DATA: - if(int(tmp_run)>int(line.run)): + if int(tmp_run) > int(line.run): tmp_run = int(line.run) - elif(int(tmp_run) < int(line.run)): + elif int(tmp_run) < int(line.run): tmp_run += line.run offset += 1 line.run = offset - - def get_replica_traces(self, recalculate:bool=False) -> pd.DataFrame: + def get_replica_traces(self, recalculate: bool = False) -> pd.DataFrame: """get_replica_traces returns a replica_traces dictionary. Parameters @@ -355,11 +391,13 @@ def get_replica_traces(self, recalculate:bool=False) -> pd.DataFrame: dictionary containing all individual replica_traces """ - if(not isinstance(self.transition_traces, pd.DataFrame) or recalculate): + if not isinstance(self.transition_traces, pd.DataFrame) or recalculate: self._caculate_transition_traces() return self.transition_traces - def get_replicaPosition_dependend_nup_ndown_for_each_state(self, time_window_size:int=-1,potential_treshold:float=None, recalculate:bool=False) -> Dict[int, Dict[str, Union[List or float]]]: + def get_replicaPosition_dependend_nup_ndown_for_each_state( + self, time_window_size: int = -1, potential_treshold: float = None, recalculate: bool = False + ) -> Dict[int, Dict[str, Union[List or float]]]: """ ..autofunction: get_replicaPosition_dependend_nup_ndown_for_each_state This function is returning the replica position visit counts by each simulation state, per state. @@ -373,14 +411,25 @@ def get_replicaPosition_dependend_nup_ndown_for_each_state(self, time_window_siz :return: returns a dict for all replica positions and their state visit counts. :rtype: Dict[int, Dict[str, Union[List or float]]] """ - if(not isinstance(self.count_state_per_position, pd.DataFrame) or recalculate): - self._calculate_ndowns_nups_for_each_state(time_stride=time_window_size, min_state_potential_treshold=potential_treshold) + if not isinstance(self.count_state_per_position, pd.DataFrame) or recalculate: + self._calculate_ndowns_nups_for_each_state( + time_stride=time_window_size, min_state_potential_treshold=potential_treshold + ) else: - if(not all([self.count_state_per_position[1]["dt"] == time_window_size, self.count_state_per_position[1]["pot_tresh"] == potential_treshold])): - self._calculate_ndowns_nups_for_each_state(time_stride=time_window_size, min_state_potential_treshold=potential_treshold) + if not all( + [ + self.count_state_per_position[1]["dt"] == time_window_size, + self.count_state_per_position[1]["pot_tresh"] == potential_treshold, + ] + ): + self._calculate_ndowns_nups_for_each_state( + time_stride=time_window_size, min_state_potential_treshold=potential_treshold + ) return self.count_state_per_position - def get_replicaPosition_dependend_nup_ndown(self, time_window_size:int=-1,potential_treshold:float=None,recalculate:bool=False) -> Dict[int, Dict[str, Union[List , pd.DataFrame, dict, float]]]: + def get_replicaPosition_dependend_nup_ndown( + self, time_window_size: int = -1, potential_treshold: float = None, recalculate: bool = False + ) -> Dict[int, Dict[str, Union[List, pd.DataFrame, dict, float]]]: """ ..autofunction: get_replicaPosition_dependend_nup_ndown This function is returning the replica position visit counts by all simulation state. @@ -394,20 +443,25 @@ def get_replicaPosition_dependend_nup_ndown(self, time_window_size:int=-1,poten :return: returns a dict for all replica positions and the visit counts. :rtype: Dict[int, Dict[str, Union[List or float]]] """ - if(not isinstance(self.replicas_pos_visit_counts, Dict)): - replicas_pos_visit_counts = {} - for replica, statistics in self.get_replicaPosition_dependend_nup_ndown_for_each_state(time_window_size=time_window_size, potential_treshold=potential_treshold, recalculate=recalculate).items(): - replica_pos_visit_counts = {replica: {"tot_nup": sum(statistics["tot_nup"]), - "tot_ndown": sum(statistics["tot_ndown"]), - "dt": statistics["dt"], - "dt_nup": list(map(lambda x: sum(x), statistics["dt_nup"])), - "dt_ndown": list(map(lambda x: sum(x), statistics["dt_ndown"]))} - } + if not isinstance(self.replicas_pos_visit_counts, Dict): + replicas_pos_visit_counts = {} + for replica, statistics in self.get_replicaPosition_dependend_nup_ndown_for_each_state( + time_window_size=time_window_size, potential_treshold=potential_treshold, recalculate=recalculate + ).items(): + replica_pos_visit_counts = { + replica: { + "tot_nup": sum(statistics["tot_nup"]), + "tot_ndown": sum(statistics["tot_ndown"]), + "dt": statistics["dt"], + "dt_nup": list(map(lambda x: sum(x), statistics["dt_nup"])), + "dt_ndown": list(map(lambda x: sum(x), statistics["dt_ndown"])), + } + } replicas_pos_visit_counts.update(replica_pos_visit_counts) return replicas_pos_visit_counts - def get_replica_roundtrips(self, recalculate:bool=False) -> Dict[int,int]: + def get_replica_roundtrips(self, recalculate: bool = False) -> Dict[int, int]: """ ..autofunction: get_replica_roundtrips This function is returning the count of rountrips (RT) for each replica. @@ -416,11 +470,11 @@ def get_replica_roundtrips(self, recalculate:bool=False) -> Dict[int,int]: :return: returns a dict for all replica and their rountrip counts. :rtype: Dict[int,int] """ - if(not isinstance(self.replica_round_trips, pd.DataFrame) or recalculate): + if not isinstance(self.replica_round_trips, pd.DataFrame) or recalculate: self._calculate_replica_roundtrips() return self.replica_round_trips - def write(self, out_path:str)->str: + def write(self, out_path: str) -> str: """ ..autofunction: Write out a repdat file to the outpath. @@ -429,16 +483,37 @@ def write(self, out_path:str)->str: :return: out_path :rtype:str """ - #content_dict{"system":..., "header":..., "data":....} + # content_dict{"system":..., "header":..., "data":....} file = open(out_path, "w") file.write(str(self.system)) file.write("\n\n") - #print header: - file.write("#"+"\t".join(["ID", "partner", "run", "li", "Ti", "Epoti", "lj", "Tj", "Epotj", "p", "s", "si", "sj", " ".join(["V"+str(i) for i in range(1, len(self.system.state_eir)+1)])])+"\n") - - #file.write("\n#"+"\t".join(self.content["header"])+"\n") + # print header: + file.write( + "#" + + "\t".join( + [ + "ID", + "partner", + "run", + "li", + "Ti", + "Epoti", + "lj", + "Tj", + "Epotj", + "p", + "s", + "si", + "sj", + " ".join(["V" + str(i) for i in range(1, len(self.system.state_eir) + 1)]), + ] + ) + + "\n" + ) + + # file.write("\n#"+"\t".join(self.content["header"])+"\n") for line in self.DATA: file.write(str(line)) file.close() - return out_path \ No newline at end of file + return out_path diff --git a/pygromos/files/otherfiles/noe_output.py b/pygromos/files/otherfiles/noe_output.py index 435043f7..e9837592 100644 --- a/pygromos/files/otherfiles/noe_output.py +++ b/pygromos/files/otherfiles/noe_output.py @@ -7,32 +7,33 @@ import numpy as np from numbers import Number -from typing import List, Dict, NamedTuple, Iterable,Union +from typing import List, Dict, NamedTuple, Iterable, Union import pandas as pd from collections import namedtuple from pygromos.files._basics import _general_gromos_file, parser from pygromos.files.blocks import _all_blocks as blocks + class NOE(_general_gromos_file._general_gromos_file): - _orig_file_path:str + _orig_file_path: str _required_blocks = ["TITLE", "AVERAGE_NOE", "NOE_VIOLATIONS", "RESTRAINT_LEGEND"] _gromos_file_ending = "noe" - #POSSIBLE GROMOS BLOCKS + # POSSIBLE GROMOS BLOCKS TITLE: blocks.TITLE AVERAGE_NOE: pd.DataFrame NOE_VIOLATIONS: pd.DataFrame RESTRAINT_LEGEND: pd.DataFrame - def __init__(self, in_value:str): + def __init__(self, in_value: str): super().__init__(in_value=in_value) def __str__(self): text = "" text += self.__getattribute__("TITLE").block_to_string() for block in sorted(self.get_block_names()): - if(block == "TITLE" or isinstance(block, type(None))): + if block == "TITLE" or isinstance(block, type(None)): continue text += str(self.__getattribute__(block)) return text @@ -50,16 +51,16 @@ def read_file(self): noe_states = {state: {}} for line in in_file_lines: - if (any([line.startswith(block) for block in known_blocks])): + if any([line.startswith(block) for block in known_blocks]): in_block = line.strip() - if (in_block in noe_states[state].keys()): + if in_block in noe_states[state].keys(): state = state + 1 noe_states.update({state: {}}) - elif (in_block and line.startswith("END")): + elif in_block and line.startswith("END"): noe_states[state].update({in_block: tmp_list}) tmp_list = [] in_block = False - elif (in_block): + elif in_block: tmp_list.append(line) # Blockify @@ -69,28 +70,28 @@ def read_file(self): ##NOE - VIOLATIONS ###read header info ###NOE Restraint - header = [s.replace("#", "") for s in - noe_states[0]["NOE VIOLATIONS"] if (s.startswith("#"))] + header = [s.replace("#", "") for s in noe_states[0]["NOE VIOLATIONS"] if (s.startswith("#"))] t_legend = [] for i, line in enumerate(header): - if ("\n" == line): + if "\n" == line: break else: t_legend.append(line) - t_legend = [[int(x.strip().split(" ")[0])] + [y for y in x.strip().split(" ")[1:] if (y != "")] for x in - t_legend] + t_legend = [ + [int(x.strip().split(" ")[0])] + [y for y in x.strip().split(" ")[1:] if (y != "")] for x in t_legend + ] for legend_entry in t_legend: - if(len(legend_entry) == 5): + if len(legend_entry) == 5: continue - elif(len(legend_entry) > 5): + elif len(legend_entry) > 5: t_ind = t_legend.index(legend_entry) t_legend.remove(legend_entry) t_legend.insert(t_ind, legend_entry[:5]) else: - raise Exception("WHAT SHALL I DO WITH THAT? "+str(legend_entry)) + raise Exception("WHAT SHALL I DO WITH THAT? " + str(legend_entry)) restraint_legend = pd.DataFrame(t_legend, columns=["Nr.", "resI", "atomI", "resJ", "atomJ"]) ##data Header @@ -109,42 +110,67 @@ def read_file(self): noe_viol = noe_data["NOE VIOLATIONS"] av_noe = noe_data["AVERAGE NOE"] no_header = list( - map(lambda x: map(float, x.strip().split()), filter(lambda y: not y.startswith("#"), noe_viol))) + map(lambda x: map(float, x.strip().split()), filter(lambda y: not y.startswith("#"), noe_viol)) + ) nvi = pd.DataFrame(no_header, columns=column_header_nviols) nvi["state"] = state no_header = list( - map(lambda x: map(float, x.strip().split()), filter(lambda y: not y.startswith("#"), av_noe))) + map(lambda x: map(float, x.strip().split()), filter(lambda y: not y.startswith("#"), av_noe)) + ) av_n = pd.DataFrame(no_header, columns=column_header_avgnoe) av_n["state"] = state - if (not isinstance(NOE_violations, pd.DataFrame)): + if not isinstance(NOE_violations, pd.DataFrame): NOE_violations = pd.DataFrame(nvi, columns=column_header_nviols + ["state"]) else: NOE_violations = NOE_violations.append(nvi, ignore_index=True) - if (not isinstance(average_NOE, pd.DataFrame)): + if not isinstance(average_NOE, pd.DataFrame): average_NOE = pd.DataFrame(av_n, columns=column_header_avgnoe + ["state"]) else: average_NOE = NOE_violations.append(av_n, ignore_index=True) - return {"TITLE":title, "AVERAGE_NOE":average_NOE, "NOE_VIOLATIONS":NOE_violations, "RESTRAINT_LEGEND":restraint_legend} + return { + "TITLE": title, + "AVERAGE_NOE": average_NOE, + "NOE_VIOLATIONS": NOE_violations, + "RESTRAINT_LEGEND": restraint_legend, + } class JVAL(_general_gromos_file._general_gromos_file): - _orig_file_path:str + _orig_file_path: str - #POSSIBLE GROMOS BLOCKS + # POSSIBLE GROMOS BLOCKS content: pd.DataFrame - _data_header: dict = {"num": int, "mol": int, "resI": int, "resN": str, - "atomNI": str, "atomNJ": str, "atomNK": str, "atomNL": str, - "atomIdI": str, "atomIdJ": str, "atomIdK": str, "atomIdL": str, - "A": float, "B": float, "C": float, - "delta": float, "J_0": float, "phi_ave": float, "phi_rmsd": float, "J_ave": float, "J_rmsd": float, - "|Jave-J0|": float} - - def __init__(self, in_value:str): + _data_header: dict = { + "num": int, + "mol": int, + "resI": int, + "resN": str, + "atomNI": str, + "atomNJ": str, + "atomNK": str, + "atomNL": str, + "atomIdI": str, + "atomIdJ": str, + "atomIdK": str, + "atomIdL": str, + "A": float, + "B": float, + "C": float, + "delta": float, + "J_0": float, + "phi_ave": float, + "phi_rmsd": float, + "J_ave": float, + "J_rmsd": float, + "|Jave-J0|": float, + } + + def __init__(self, in_value: str): super().__init__(in_value=in_value) self.average_J_deviation = np.mean(self.content["J_ave"] - self.content["J_0"]) @@ -154,19 +180,27 @@ def __init__(self, in_value:str): def __str__(self): text = "" - text += "#\taverage_J_deviation\t"+str(self.average_J_deviation)+"\n" - text += "#\taverage_abs_deviation\t"+str(self.average_abs_deviation)+"\n" - text += "#\troot_mean_square_deviation\t"+str(self.root_mean_square_deviation)+"\n" - text += "#\troot_mean_square_deviation_over_deviations\t"+str(self.root_mean_square_deviation_over_deviations)+"\n" - text += self.content.to_string()+"\n" + text += "#\taverage_J_deviation\t" + str(self.average_J_deviation) + "\n" + text += "#\taverage_abs_deviation\t" + str(self.average_abs_deviation) + "\n" + text += "#\troot_mean_square_deviation\t" + str(self.root_mean_square_deviation) + "\n" + text += ( + "#\troot_mean_square_deviation_over_deviations\t" + + str(self.root_mean_square_deviation_over_deviations) + + "\n" + ) + text += self.content.to_string() + "\n" return text - def write(self, out_path:str) ->str: + def write(self, out_path: str) -> str: text = "" - text += "#\taverage_J_deviation\t"+str(self.average_J_deviation)+"\n" - text += "#\taverage_abs_deviation\t"+str(self.average_abs_deviation)+"\n" - text += "#\troot_mean_square_deviation\t"+str(self.root_mean_square_deviation)+"\n" - text += "#\troot_mean_square_deviation_over_deviations\t"+str(self.root_mean_square_deviation_over_deviations)+"\n" + text += "#\taverage_J_deviation\t" + str(self.average_J_deviation) + "\n" + text += "#\taverage_abs_deviation\t" + str(self.average_abs_deviation) + "\n" + text += "#\troot_mean_square_deviation\t" + str(self.root_mean_square_deviation) + "\n" + text += ( + "#\troot_mean_square_deviation_over_deviations\t" + + str(self.root_mean_square_deviation_over_deviations) + + "\n" + ) self.content.to_csv(out_path, header=text) return out_path @@ -181,18 +215,18 @@ def __iter__(self): def read_file(self): - jval_file = open(self._orig_file_path, "r") + jval_file = open(self._orig_file_path, "r") jval_lines = jval_file.readlines() jval_file.close() in_block = False data_lines = [] for line in jval_lines: - if (line.startswith("# num mol")): + if line.startswith("# num mol"): in_block = True - elif (line.startswith("#") or line == "\n"): + elif line.startswith("#") or line == "\n": continue - elif (in_block): + elif in_block: data_lines.append(line.strip().split()) data = pd.DataFrame(data=data_lines, columns=self._data_header) diff --git a/pygromos/files/otherfiles/repdat.py b/pygromos/files/otherfiles/repdat.py index 33538ed4..ba764f76 100644 --- a/pygromos/files/otherfiles/repdat.py +++ b/pygromos/files/otherfiles/repdat.py @@ -19,9 +19,10 @@ class Repdat: class Repdat(_general_gromos_file._general_gromos_file): # """Replica exchange statistic file - This class is a representation for all transition information during a replica exchange run. it adds some useful functionality. + This class is a representation for all transition information during a replica exchange run. it adds some useful functionality. """ + _gromos_file_ending: str = "repstat" SYSTEM: blocks.repex_system DATA: pd.DataFrame @@ -36,7 +37,7 @@ class Repdat(_general_gromos_file._general_gromos_file): # replica_round_trips: Dict[int, int] = None def __init__(self, input_path: str): - """ Repdat_Constructor + """Repdat_Constructor Parameters ---------- @@ -73,7 +74,7 @@ def _clean_replica_round_trips(self, replica_round_trips: Dict[int, int]) -> Dic # clean up indices that are -1 clean_replica_round_trips = {} for key, item in replica_round_trips.items(): - if (item != -1): + if item != -1: clean_replica_round_trips.update({key: item}) else: clean_replica_round_trips.update({key: 0}) @@ -91,19 +92,21 @@ def _caculate_transition_traces(self) -> None: None """ - replicas = len(self.system.s) # follow transitions of one state - transition_dict = {x: x for x in range(1, replicas + 1)} # keeps track of unique id and current replica position. + transition_dict = { + x: x for x in range(1, replicas + 1) + } # keeps track of unique id and current replica position. tmp_dict = {x: x for x in range(1, replicas + 1)} - transition_result_dict = {x: {"trial": [], "position": [], "state_pot": []} for x in - range(1, replicas + 1)} # init transition dicts following one replica with inital start + transition_result_dict = { + x: {"trial": [], "position": [], "state_pot": []} for x in range(1, replicas + 1) + } # init transition dicts following one replica with inital start # go through repda and count tmp_run = 1 for index, row in self.DATA.iterrows(): - if (tmp_run != row.run): # new trial + if tmp_run != row.run: # new trial transition_dict = tmp_dict tmp_dict = {x: x for x in range(1, replicas + 1)} tmp_run = row.run @@ -111,7 +114,7 @@ def _caculate_transition_traces(self) -> None: # Exchange Replica replica = int(transition_dict[int(row.ID)]) # get the replica unique id ##record Exchange - if (row.s == 1): # only hit when exchange and not partner already exchangeds + if row.s == 1: # only hit when exchange and not partner already exchangeds # new_pos transition_result_dict[replica]["trial"].append(int(row.run)) transition_result_dict[replica]["position"].append(int(row.partner)) @@ -134,7 +137,9 @@ def _caculate_transition_traces(self) -> None: [df.insert(0, "replicaID", replicaID) for replicaID, df in traces.items()] self.transition_traces = pd.concat(traces) - def _calculate_ndowns_nups_for_each_state(self, time_stride: int = -1, min_state_potential_treshold: float = None, verbose: bool = False): + def _calculate_ndowns_nups_for_each_state( + self, time_stride: int = -1, min_state_potential_treshold: float = None, verbose: bool = False + ): """_calculate_ndowns_nups_for_each_state calculates the visit counts for each replicaID position (Temperature or s_value). @@ -164,31 +169,41 @@ def _calculate_ndowns_nups_for_each_state(self, time_stride: int = -1, min_state num_states = len(self.system.state_eir) num_replica = len(self.system.s) - if (time_stride < 1): + if time_stride < 1: time_stride = 1 # arbitrary window size value, that seems reasonable! len(replica_traces[list(replica_traces.keys())[0]]["trial"]) * 0.01 extreme_positions = (1, num_replica) # gives the extreme values of the replicaID dist - replica_extreme_position_memory = {replica: -1 for replica in range(1, num_replica + 1)} # which replicaID visited which extreme? - replica_extreme_position_memory.update({1: extreme_positions[0], num_replica: extreme_positions[1]}) # init pos1 and last one + replica_extreme_position_memory = { + replica: -1 for replica in range(1, num_replica + 1) + } # which replicaID visited which extreme? + replica_extreme_position_memory.update( + {1: extreme_positions[0], num_replica: extreme_positions[1]} + ) # init pos1 and last one # result vars # for easier keeping track of state indices state_index = {key: key for key in range(num_states)} - if (min_state_potential_treshold != None): # add an undef state if multiple residues are below threshold. + if min_state_potential_treshold != None: # add an undef state if multiple residues are below threshold. state_index.update({"undefined": num_states}) num_states += 1 - count_state_perpos = {positionID: {"tot_nup": [0 for state in state_index], - "tot_ndown": [0 for state in state_index], - "dt": time_stride, - "pot_tresh": min_state_potential_treshold, - "states_index": state_index, - "dt_nup": [[0 for state in state_index]], - "dt_ndown": [[0 for state in state_index]]} - for positionID in range(1, num_replica + 1)} - - if verbose: print("general: ", extreme_positions) - if verbose: print("time_window_size: ", time_stride) + count_state_perpos = { + positionID: { + "tot_nup": [0 for state in state_index], + "tot_ndown": [0 for state in state_index], + "dt": time_stride, + "pot_tresh": min_state_potential_treshold, + "states_index": state_index, + "dt_nup": [[0 for state in state_index]], + "dt_ndown": [[0 for state in state_index]], + } + for positionID in range(1, num_replica + 1) + } + + if verbose: + print("general: ", extreme_positions) + if verbose: + print("time_window_size: ", time_stride) # if verbose: print("INITIAL") # if verbose: print("Initial count_per_repPos\n", count_state_per_position) # if verbose: print("Initial current_extremePos_replica\n", replica_extreme_position_memory) @@ -202,28 +217,34 @@ def _calculate_ndowns_nups_for_each_state(self, time_stride: int = -1, min_state count_state_perpos[position]["dt_ndown"].append([0 for state in state_index]) count_state_perpos[position]["dt_nup"].append([0 for state in state_index]) - if (position in extreme_positions and replica_extreme_position_memory[replicaID] != position): + if position in extreme_positions and replica_extreme_position_memory[replicaID] != position: replica_extreme_position_memory.update({replicaID: position}) replica_round_trips[replicaID] += 1 # This replicaID has already seen an extreme pos - if (replica_extreme_position_memory[replicaID] in extreme_positions): + if replica_extreme_position_memory[replicaID] in extreme_positions: # who is the active state? - if (min_state_potential_treshold != None): # NEW shall no other state be in an undersampling situation? - undersampling_state_energies = [float(val) for val in list(pot_energies.values()) if (float(val) < min_state_potential_treshold)] - if (1 == len(undersampling_state_energies)): # clean active states - only one state at a time underSampling + if min_state_potential_treshold != None: # NEW shall no other state be in an undersampling situation? + undersampling_state_energies = [ + float(val) for val in list(pot_energies.values()) if (float(val) < min_state_potential_treshold) + ] + if 1 == len( + undersampling_state_energies + ): # clean active states - only one state at a time underSampling active_state = undersampling_state_energies.index(min(undersampling_state_energies)) else: # no clear state presen skip active_state = state_index["undefined"] else: - undersampling_state_energies = [float(val) for val in list(pot_energies.values())] # if(float(val) < 200)] + undersampling_state_energies = [ + float(val) for val in list(pot_energies.values()) + ] # if(float(val) < 200)] active_state = undersampling_state_energies.index(min(undersampling_state_energies)) # determine if replicaID comes from top or bottom and add +1 to stat - if (replica_extreme_position_memory[replicaID] == extreme_positions[0]): # coming from top + if replica_extreme_position_memory[replicaID] == extreme_positions[0]: # coming from top count_state_perpos[position]["tot_ndown"][active_state] += 1 count_state_perpos[position]["dt_ndown"][-1][active_state] += 1 - elif (replica_extreme_position_memory[replicaID] == extreme_positions[1]): # coming_from bottom + elif replica_extreme_position_memory[replicaID] == extreme_positions[1]: # coming_from bottom count_state_perpos[position]["tot_nup"][active_state] += 1 count_state_perpos[position]["dt_nup"][-1][active_state] += 1 else: # NEW has never seen any thing @@ -231,12 +252,22 @@ def _calculate_ndowns_nups_for_each_state(self, time_stride: int = -1, min_state else: continue - if verbose: print("\nFINAL") - if verbose: print("Final extreme_positions", replica_extreme_position_memory) - if verbose: print("Final position counts totup/totdown: ", - [(count_state_perpos[pos]["tot_nup"], count_state_perpos[pos]["tot_ndown"]) for pos in count_state_perpos]) - if verbose: print("Final positoin counts keys", count_state_perpos[1].keys()) - if verbose: print("counted rountrips per replicaID!: ", replica_round_trips) + if verbose: + print("\nFINAL") + if verbose: + print("Final extreme_positions", replica_extreme_position_memory) + if verbose: + print( + "Final position counts totup/totdown: ", + [ + (count_state_perpos[pos]["tot_nup"], count_state_perpos[pos]["tot_ndown"]) + for pos in count_state_perpos + ], + ) + if verbose: + print("Final positoin counts keys", count_state_perpos[1].keys()) + if verbose: + print("counted rountrips per replicaID!: ", replica_round_trips) # store trajs in pd.dataframes. tmp_counts = self._clean_replica_round_trips(replica_round_trips) @@ -270,8 +301,12 @@ def _calculate_replica_roundtrips(self): num_replica = len(self.system.s) extreme_positions = (1, num_replica) # gives the extreme values of the replica dist - replica_extreme_position_memory = {replica: -1 for replica in range(1, num_replica + 1)} # which replica visited which extreme? - replica_extreme_position_memory.update({1: extreme_positions[0], num_replica: extreme_positions[1]}) # init pos1 and last one + replica_extreme_position_memory = { + replica: -1 for replica in range(1, num_replica + 1) + } # which replica visited which extreme? + replica_extreme_position_memory.update( + {1: extreme_positions[0], num_replica: extreme_positions[1]} + ) # init pos1 and last one # as side product easily the round trips can be calculated! replica_round_trips = {replica: -1 for replica in range(1, num_replica + 1)} @@ -279,11 +314,14 @@ def _calculate_replica_roundtrips(self): replica_round_trips[num_replica] = 0 # only go over_extreme postitions. - extreme_position_trace = replica_traces.loc[replica_traces.position.isin(extreme_positions)].sort_values("trial") + extreme_position_trace = replica_traces.loc[replica_traces.position.isin(extreme_positions)].sort_values( + "trial" + ) for index, (replicaID, trial, position, pot_energies) in extreme_position_trace.sort_values( - "trial").iterrows(): # go through each replica trace + "trial" + ).iterrows(): # go through each replica trace # print(trial, position, pot_energies) - if (position in extreme_positions and replica_extreme_position_memory[replicaID] != position): + if position in extreme_positions and replica_extreme_position_memory[replicaID] != position: replica_extreme_position_memory.update({replicaID: position}) replica_round_trips[replicaID] += 1 else: @@ -308,7 +346,7 @@ def append(self, repdat: (List[Repdat] or Repdat)): # if(self.system != repdat.system): # raise ValueError("The two repdats seem not to come from the same simulation, as the system settings are different!") - if (not isinstance(repdat, List)): + if not isinstance(repdat, List): repdat = [repdat] self.DATA = pd.concat([self.DATA, *map(lambda x: x.DATA, repdat)], ignore_index=True) @@ -316,14 +354,14 @@ def append(self, repdat: (List[Repdat] or Repdat)): def clean_file_runs(self, starting_trial: float = 1): """clean_file - Updates the run numbers to be continous sequential. (for example needed for concatenation) - Parameters - ---------- - starting_trial: int, optional + Updates the run numbers to be continous sequential. (for example needed for concatenation) + Parameters + ---------- + starting_trial: int, optional """ - self.DATA.run = pd.Series(map(lambda i: starting_trial+(int(i) // len(self.system.s)), self.DATA.index)) + self.DATA.run = pd.Series(map(lambda i: starting_trial + (int(i) // len(self.system.s)), self.DATA.index)) def get_replica_traces(self, recalculate: bool = False) -> pd.DataFrame: """get_replica_traces @@ -339,12 +377,13 @@ def get_replica_traces(self, recalculate: bool = False) -> pd.DataFrame: dictionary containing all individual replica_traces """ - if (not isinstance(self.transition_traces, pd.DataFrame) or recalculate): + if not isinstance(self.transition_traces, pd.DataFrame) or recalculate: self._caculate_transition_traces() return self.transition_traces - def get_replicaPosition_dependend_nup_ndown_for_each_state(self, time_window_size: int = -1, potential_treshold: float = None, - recalculate: bool = False) -> Dict[int, Dict[str, Union[List or float]]]: + def get_replicaPosition_dependend_nup_ndown_for_each_state( + self, time_window_size: int = -1, potential_treshold: float = None, recalculate: bool = False + ) -> Dict[int, Dict[str, Union[List or float]]]: """get_replicaPosition_dependend_nup_ndown_for_each_state This function is returning the replica position visit counts by each simulation state, per state. @@ -362,16 +401,25 @@ def get_replicaPosition_dependend_nup_ndown_for_each_state(self, time_window_siz returns a dict for all replica positions and their state visit counts. """ - if (not isinstance(self.count_state_per_position, pd.DataFrame) or recalculate): - self._calculate_ndowns_nups_for_each_state(time_stride=time_window_size, min_state_potential_treshold=potential_treshold) + if not isinstance(self.count_state_per_position, pd.DataFrame) or recalculate: + self._calculate_ndowns_nups_for_each_state( + time_stride=time_window_size, min_state_potential_treshold=potential_treshold + ) else: - if (not all([self.count_state_per_position[1]["dt"] == time_window_size, - self.count_state_per_position[1]["pot_tresh"] == potential_treshold])): - self._calculate_ndowns_nups_for_each_state(time_stride=time_window_size, min_state_potential_treshold=potential_treshold) + if not all( + [ + self.count_state_per_position[1]["dt"] == time_window_size, + self.count_state_per_position[1]["pot_tresh"] == potential_treshold, + ] + ): + self._calculate_ndowns_nups_for_each_state( + time_stride=time_window_size, min_state_potential_treshold=potential_treshold + ) return self.count_state_per_position - def get_replicaPosition_dependend_nup_ndown(self, time_window_size: int = -1, potential_treshold: float = None, recalculate: bool = False) -> \ - Dict[int, Dict[str, Union[List, pd.DataFrame, dict, float]]]: + def get_replicaPosition_dependend_nup_ndown( + self, time_window_size: int = -1, potential_treshold: float = None, recalculate: bool = False + ) -> Dict[int, Dict[str, Union[List, pd.DataFrame, dict, float]]]: """get_replicaPosition_dependend_nup_ndown This function is returning the replica position visit counts by all simulation state. @@ -390,17 +438,20 @@ def get_replicaPosition_dependend_nup_ndown(self, time_window_size: int = -1, po returns a dict for all replica positions and the visit counts. """ - if (not isinstance(self.replicas_pos_visit_counts, Dict)): + if not isinstance(self.replicas_pos_visit_counts, Dict): replicas_pos_visit_counts = {} - for replica, statistics in self.get_replicaPosition_dependend_nup_ndown_for_each_state(time_window_size=time_window_size, - potential_treshold=potential_treshold, - recalculate=recalculate).items(): - replica_pos_visit_counts = {replica: {"tot_nup": sum(statistics["tot_nup"]), - "tot_ndown": sum(statistics["tot_ndown"]), - "dt": statistics["dt"], - "dt_nup": list(map(lambda x: sum(x), statistics["dt_nup"])), - "dt_ndown": list(map(lambda x: sum(x), statistics["dt_ndown"]))} - } + for replica, statistics in self.get_replicaPosition_dependend_nup_ndown_for_each_state( + time_window_size=time_window_size, potential_treshold=potential_treshold, recalculate=recalculate + ).items(): + replica_pos_visit_counts = { + replica: { + "tot_nup": sum(statistics["tot_nup"]), + "tot_ndown": sum(statistics["tot_ndown"]), + "dt": statistics["dt"], + "dt_nup": list(map(lambda x: sum(x), statistics["dt_nup"])), + "dt_ndown": list(map(lambda x: sum(x), statistics["dt_ndown"])), + } + } replicas_pos_visit_counts.update(replica_pos_visit_counts) return replicas_pos_visit_counts @@ -421,7 +472,7 @@ def get_replica_roundtrips(self, recalculate: bool = False) -> Dict[int, int]: returns a dict for all replica and their rountrip counts. """ - if (not isinstance(self.replica_round_trips, pd.DataFrame) or recalculate): + if not isinstance(self.replica_round_trips, pd.DataFrame) or recalculate: self._calculate_replica_roundtrips() return self.replica_round_trips @@ -443,11 +494,11 @@ def write(self, out_path: str) -> str: file.write("#======================\n") file.write("#" + self.system.name + "\n") file.write("#======================\n") - file.writelines(map(lambda x: "#"+x+"\n", str(self.system).split("\n"))) + file.writelines(map(lambda x: "#" + x + "\n", str(self.system).split("\n"))) file.write("\n") print("DATA COLS: ", self.DATA.columns) - out_df = self.DATA.join(pd.DataFrame(self.DATA.pop('state_potentials').tolist())) - file.write("\t".join(out_df.columns)+ "\n") + out_df = self.DATA.join(pd.DataFrame(self.DATA.pop("state_potentials").tolist())) + file.write("\t".join(out_df.columns) + "\n") out_df.to_csv(file, sep="\t", header=False, index=False) file.close() diff --git a/pygromos/files/otherfiles/residue_library.py b/pygromos/files/otherfiles/residue_library.py index a0d12a37..8be3b5b9 100644 --- a/pygromos/files/otherfiles/residue_library.py +++ b/pygromos/files/otherfiles/residue_library.py @@ -5,7 +5,7 @@ Author: Benjamin Ries """ -#imports +# imports from typing import Union from pygromos.files.blocks import _all_blocks as blocks from pygromos.files._basics import parser @@ -14,15 +14,16 @@ from pygromos.data import pdb_lib + class residue_library(_general_gromos_file._general_gromos_file): required_blocks = ["TITLE", "RESIDUENAMELIB", "ATOMNAMELIB"] RESIDUENAMELIB: blocks.RESIDUENAMELIB ATOMNAMELIB: blocks.ATOMNAMELIB - verbose : bool = False + verbose: bool = False _gromos_file_ending = "res" - def __init__(self, in_value:Union[str, dict]=pdb_lib): + def __init__(self, in_value: Union[str, dict] = pdb_lib): """ This class represents a file that is used for the gromosPP program - pdb2g96 it contains two blocks for residue naming and atom naming @@ -33,19 +34,22 @@ def __init__(self, in_value:Union[str, dict]=pdb_lib): """ self.blocksset = [] - if(type(in_value) is str): + if type(in_value) is str: self.path = in_value self.read_resnlib(in_value) - elif(in_value==None): - if(self.verbose): print("Warning!: generated empty REsidue Lib obj!") + elif in_value == None: + if self.verbose: + print("Warning!: generated empty REsidue Lib obj!") self.TITLE = blocks.TITLE(content="New empyt resn_lib-file\n\tgenerated with PyGromosTools.\n") self.RESIDUENAMELIB = blocks.RESIDUENAMELIB({}) self.ATOMNAMELIB = blocks.ATOMNAMELIB({}) else: - raise IOError("pertubation_topology class got "+str(type(in_value))+" as input. Unknown input type for disres.") + raise IOError( + "pertubation_topology class got " + str(type(in_value)) + " as input. Unknown input type for disres." + ) - def read_resnlib(self, path:str): + def read_resnlib(self, path: str): data = parser.read_general_gromos_file(path) - #add _blocks as attribute to objects + # add _blocks as attribute to objects for key, sub_content in data.items(): self.add_block(blocktitle=key, content=sub_content) diff --git a/pygromos/files/qmmm/qmmm.py b/pygromos/files/qmmm/qmmm.py index 68b703e6..2faa7a7e 100644 --- a/pygromos/files/qmmm/qmmm.py +++ b/pygromos/files/qmmm/qmmm.py @@ -6,22 +6,25 @@ from pygromos.files.blocks import qmmm_blocks as blocks - class QMMM(_general_gromos_file._general_gromos_file): - _gromos_file_ending:str = "qmmm" + _gromos_file_ending: str = "qmmm" - _orig_file_path:str - path:str - _required_blocks = ["TITLE", "QMZONE", "QMUNIT"] # Not yet implemented; taken from "class Imd", other blocks are e.g. "XTBELEMENTS" and "ORCAELEMENTS" + _orig_file_path: str + path: str + _required_blocks = [ + "TITLE", + "QMZONE", + "QMUNIT", + ] # Not yet implemented; taken from "class Imd", other blocks are e.g. "XTBELEMENTS" and "ORCAELEMENTS" # POSSIBLE GROMOS BLOCKS - TITLE: blocks.TITLE + TITLE: blocks.TITLE QMZONE: blocks.QMZONE QMUNIT: blocks.QMUNIT # One of those blocks should be available # Consult the Gromos documentation for more details - # Also consult the corresponding QMMM block in imd files + # Also consult the corresponding QMMM block in imd files MNDOELEMENTS: blocks.MNDOELEMENTS = None TURBOMOLEELEMENTS: blocks.TURBOMOLEELEMENTS = None DFTBELEMENTS: blocks.DFTBELEMENTS = None @@ -29,44 +32,44 @@ class QMMM(_general_gromos_file._general_gromos_file): ORCAELEMENTS: blocks.ORCAELEMENTS = None XTBELEMENTS: blocks.XTBELEMENTS = None - def __init__(self, in_value:str, _future_file:bool=False): + def __init__(self, in_value: str, _future_file: bool = False): super().__init__(in_value=in_value, _future_file=_future_file) - #TODO: maybe somebody can make a better solution for this. This is a ugly fix to unify the structure of the blocks + # TODO: maybe somebody can make a better solution for this. This is a ugly fix to unify the structure of the blocks for block in sorted(self.get_block_names()): setattr(self, block, deepcopy(getattr(self, block))) # Perform some sanity checks # only if not a future file and if there is at least one block # (to avoid being run while deep_copy) - if(not _future_file and len(self.get_block_names()) > 0): + if not _future_file and len(self.get_block_names()) > 0: self._health_check() def __str__(self): text = "" - if(hasattr(self, "TITLE")): + if hasattr(self, "TITLE"): text += self.__getattribute__("TITLE").block_to_string() for block in sorted(self.get_block_names()): - if(block == "TITLE" or isinstance(block, type(None))): + if block == "TITLE" or isinstance(block, type(None)): continue text += str(self.__getattribute__(block)) return text def read_file(self): - #Read blocks to string + # Read blocks to string data = parser.read_general_gromos_file(self._orig_file_path) - #translate the string subblocks + # translate the string subblocks blocks = {} for block_title in data: self.add_block(blocktitle=block_title, content=data[block_title]) blocks.update({block_title: self.__getattribute__(block_title)}) return blocks - def get_qm_engines(self)->List[str]: + def get_qm_engines(self) -> List[str]: """ Returns the QM engine used - + Returns ------- List[str] @@ -78,10 +81,13 @@ def get_qm_engines(self)->List[str]: def _health_check(self): """ Runs tests on the integrity of the file and spits out warnings - members = [attr for attr in dir(self) if not callable(getattr(self, attr)) and attr.endswith("ELEMENTS")] + members = [attr for attr in dir(self) if not callable(getattr(self, attr)) and attr.endswith("ELEMENTS")] """ members = [element for element in self.get_block_names() if element.endswith("ELEMENTS")] - if(len(members) > 1): - warnings.warn("Declaration of more than one (QMENGINE)ELEMENTS blocks in QM/MM specification file detected: " + ", ".join(members)) - elif(len(members) < 1): - warnings.warn("No (QMENGINE)ELEMENTS block in QM/MM specification file detected.") \ No newline at end of file + if len(members) > 1: + warnings.warn( + "Declaration of more than one (QMENGINE)ELEMENTS blocks in QM/MM specification file detected: " + + ", ".join(members) + ) + elif len(members) < 1: + warnings.warn("No (QMENGINE)ELEMENTS block in QM/MM specification file detected.") diff --git a/pygromos/files/simulation_parameters/imd.py b/pygromos/files/simulation_parameters/imd.py index b44207d5..3e7518cd 100644 --- a/pygromos/files/simulation_parameters/imd.py +++ b/pygromos/files/simulation_parameters/imd.py @@ -15,7 +15,8 @@ from pygromos.files.blocks import imd_blocks as blocks from pygromos.utils import amino_acids as aa -def nice_s_vals(svals:Iterable, base10=False) ->list: + +def nice_s_vals(svals: Iterable, base10=False) -> list: """ Parameters @@ -29,25 +30,35 @@ def nice_s_vals(svals:Iterable, base10=False) ->list: """ nicer_labels = [] - if(base10): + if base10: for val in svals: - if(float(np.log10(val)).is_integer() or val == min(svals)): - nicer_labels.append(round(val, str(val).count("0")+3)) + if float(np.log10(val)).is_integer() or val == min(svals): + nicer_labels.append(round(val, str(val).count("0") + 3)) else: nicer_labels.append("") else: for val in svals: - nicer_labels.append(round(float(val), str(val).count("0")+2)) + nicer_labels.append(round(float(val), str(val).count("0") + 2)) return nicer_labels -class Imd(_general_gromos_file._general_gromos_file): - _gromos_file_ending:str = "imd" - - _orig_file_path:str - path:str - _required_blocks = ["TITLE", "SYSTEM", "STEP", "BOUNDCOND", "FORCE", "CONSTRAINT", "PAIRLIST", "NONBONDED"] # Not yet implemented - #POSSIBLE GROMOS BLOCKS +class Imd(_general_gromos_file._general_gromos_file): + _gromos_file_ending: str = "imd" + + _orig_file_path: str + path: str + _required_blocks = [ + "TITLE", + "SYSTEM", + "STEP", + "BOUNDCOND", + "FORCE", + "CONSTRAINT", + "PAIRLIST", + "NONBONDED", + ] # Not yet implemented + + # POSSIBLE GROMOS BLOCKS TITLE: blocks.TITLE STEP: blocks.STEP @@ -58,7 +69,7 @@ class Imd(_general_gromos_file._general_gromos_file): FORCE: blocks.FORCE ENERGYMIN: blocks.ENERGYMIN - EDS:blocks.EDS + EDS: blocks.EDS CONSTRAINT: blocks.CONSTRAINT BOUNDCOND: blocks.BOUNDCOND @@ -76,24 +87,24 @@ class Imd(_general_gromos_file._general_gromos_file): REPLICA_EDS: blocks.REPLICA_EDS NEW_REPLICA_EDS: blocks.NEW_REPLICA_EDS - + REPLICA: blocks.REPLICA QMMM: blocks.QMMM - def __init__(self, in_value:str, _future_file:bool=False): + def __init__(self, in_value: str, _future_file: bool = False): super().__init__(in_value=in_value, _future_file=_future_file) - #TODO: maybe somebody can make a better solution for this. This is a ugly fix to unify the structure of the blocks + # TODO: maybe somebody can make a better solution for this. This is a ugly fix to unify the structure of the blocks for block in sorted(self.get_block_names()): setattr(self, block, deepcopy(getattr(self, block))) def __str__(self): text = "" - if(hasattr(self, "TITLE")): + if hasattr(self, "TITLE"): text += self.__getattribute__("TITLE").block_to_string() for block in sorted(self.get_block_names()): - if(block == "TITLE" or isinstance(block, type(None))): + if block == "TITLE" or isinstance(block, type(None)): continue text += str(self.__getattribute__(block)) return text @@ -107,8 +118,17 @@ def read_file(self): raise Exception("Error while reading file: " + str(err)) return {} - def edit_EDS(self, NUMSTATES:int, S:float, EIR:list, EDS:int=1, ALPHLJ:float=0.0, ALPHC:float=0.0, FUNCTIONAL:int=1): - if(hasattr(self, "eds_block")): + def edit_EDS( + self, + NUMSTATES: int, + S: float, + EIR: list, + EDS: int = 1, + ALPHLJ: float = 0.0, + ALPHC: float = 0.0, + FUNCTIONAL: int = 1, + ): + if hasattr(self, "eds_block"): self.EDS.ALPHLJ = ALPHLJ self.EDS.ALPHC = ALPHC self.EDS.FUNCTIONAL = FUNCTIONAL @@ -118,66 +138,84 @@ def edit_EDS(self, NUMSTATES:int, S:float, EIR:list, EDS:int=1, ALPHLJ:float=0.0 else: print("Setting new EDS_block") - if(type(EIR) == float or type(EIR) == str or type(EIR) == int): + if type(EIR) == float or type(EIR) == str or type(EIR) == int: EIR = [float(EIR) for x in range(NUMSTATES)] gromos_name = "EDS" setattr(self, gromos_name, blocks.EDS(NUMSTATES, S, EIR, EDS, ALPHLJ, ALPHC, FUNCTIONAL)) - def randomize_seed(self): self.INITIALISE.IG = np.random.randint(low=0, high=999999) - def edit_REEDS(self, REEDS:(bool or int)=None, NUMSTATES:int=None, SVALS: (Number, List[Number])=None, EIR:(Number or Iterable[Number])=None, - NRETRIAL:int=None, NREQUIL:int=None, CONT:(bool, int)=None, EDS_STAT_OUT:(bool, int)=None, - RETS:List[float]= None, RET:int=None, NATOM:int=None) : #TODO: old params - to be REMOVED! + def edit_REEDS( + self, + REEDS: (bool or int) = None, + NUMSTATES: int = None, + SVALS: (Number, List[Number]) = None, + EIR: (Number or Iterable[Number]) = None, + NRETRIAL: int = None, + NREQUIL: int = None, + CONT: (bool, int) = None, + EDS_STAT_OUT: (bool, int) = None, + RETS: List[float] = None, + RET: int = None, + NATOM: int = None, + ): # TODO: old params - to be REMOVED! # specific relations are rescued here reeds_block = self.REPLICA_EDS print(type(reeds_block)) - - if(isinstance(REEDS, bool)): + if isinstance(REEDS, bool): reeds_block.REEDS = REEDS - if(isinstance(NUMSTATES, (Number, str))): + if isinstance(NUMSTATES, (Number, str)): reeds_block.NUMSTATES = NUMSTATES - if(isinstance(SVALS, Iterable)): #edit SVALS + if isinstance(SVALS, Iterable): # edit SVALS SVALS = nice_s_vals(SVALS) reeds_block.RES = list(map(str, SVALS)) - reeds_block.NRES = len(SVALS) #adjust number of Svals + reeds_block.NRES = len(SVALS) # adjust number of Svals - if(isinstance(EIR, (Number, Iterable))): #expand energy offsets to new s value ammount + if isinstance(EIR, (Number, Iterable)): # expand energy offsets to new s value ammount # set new EIR with 3 different types of input (single number, vector or matrix) EIR_matrix = [] # single number - if(isinstance(EIR, Number)): # depends on SVALS and NRES + if isinstance(EIR, Number): # depends on SVALS and NRES EIR_vector = [EIR for x in range(reeds_block.NUMSTATES)] for z in EIR_vector: EIR_matrix.append([z for i in range(int(reeds_block.NRES))]) # vector or matrix - elif(isinstance(EIR, Iterable) and len(EIR) == int(reeds_block.NUMSTATES) and all([isinstance(x, Number) for x in EIR])): + elif ( + isinstance(EIR, Iterable) + and len(EIR) == int(reeds_block.NUMSTATES) + and all([isinstance(x, Number) for x in EIR]) + ): for z in EIR: EIR_matrix.append([z for i in range(int(reeds_block.NRES))]) else: raise Exception( - "not enough EIR-vals for making REEDS Block. Got " + str(len(EIR)) + " for " + str( - reeds_block.NRES) + " SVals\n Number of states: "+str(reeds_block.NUMSTATES)) + "not enough EIR-vals for making REEDS Block. Got " + + str(len(EIR)) + + " for " + + str(reeds_block.NRES) + + " SVals\n Number of states: " + + str(reeds_block.NUMSTATES) + ) reeds_block.EIR = EIR_matrix else: - if(any([len(row)!= len(SVALS) for row in reeds_block.EIR])): + if any([len(row) != len(SVALS) for row in reeds_block.EIR]): newEIR = [] for EIR_row in reeds_block.EIR: newEIRrow = [EIR_row[0] for r in range(len(SVALS))] newEIR.append(newEIRrow) reeds_block.EIR = newEIR - if(isinstance(EIR, (Number , Iterable))): + if isinstance(EIR, (Number, Iterable)): EIR_matrix = [] print(EIR) # single number @@ -188,36 +226,48 @@ def edit_REEDS(self, REEDS:(bool or int)=None, NUMSTATES:int=None, SVALS: (Numbe EIR_matrix.append([z for i in range(int(reeds_block.NRES))]) # vector - elif (isinstance(EIR, Iterable) and len(EIR) == int(reeds_block.NUMSTATES) and all( - [isinstance(x, (Number, str)) for x in EIR])): + elif ( + isinstance(EIR, Iterable) + and len(EIR) == int(reeds_block.NUMSTATES) + and all([isinstance(x, (Number, str)) for x in EIR]) + ): for z in EIR: EIR_matrix.append([float(z) for i in range(int(reeds_block.NRES))]) # matrix - elif(isinstance(EIR, Iterable) and all([isinstance(x, Iterable) and all([isinstance(y, (Number, str)) for y in x]) for x in EIR])): - if (len(self.REPLICA_EDS.NRES) == len(EIR)): - EIR = np.array(EIR).T - EIR_matrix = list(map(lambda x: list(map(float, x)), EIR)) + elif isinstance(EIR, Iterable) and all( + [isinstance(x, Iterable) and all([isinstance(y, (Number, str)) for y in x]) for x in EIR] + ): + if len(self.REPLICA_EDS.NRES) == len(EIR): + EIR = np.array(EIR).T + EIR_matrix = list(map(lambda x: list(map(float, x)), EIR)) else: raise Exception( - "not enough EIR-vals for making REEDS Block. Got " + str(len(EIR)) + " for " + str( - reeds_block.NRES) + " SVals and states: "+str(reeds_block.NUMSTATES)+ "\n") + "not enough EIR-vals for making REEDS Block. Got " + + str(len(EIR)) + + " for " + + str(reeds_block.NRES) + + " SVals and states: " + + str(reeds_block.NUMSTATES) + + "\n" + ) reeds_block.EIR = EIR_matrix - if (isinstance(NRETRIAL, (str, int))): + if isinstance(NRETRIAL, (str, int)): reeds_block.NRETRIAL = NRETRIAL - if (isinstance(NREQUIL, (str, int))): + if isinstance(NREQUIL, (str, int)): reeds_block.NREQUIL = NREQUIL - if (isinstance(CONT, (str, int, bool))): + if isinstance(CONT, (str, int, bool)): reeds_block.CONT = CONT - if (isinstance(EDS_STAT_OUT, (str, int, bool))): + if isinstance(EDS_STAT_OUT, (str, int, bool)): reeds_block.EDS_STAT_OUT = EDS_STAT_OUT - - def write_json(self,out_path:str): + def write_json(self, out_path: str): d = copy.deepcopy(vars(self)) for v in vars(self): - if (isinstance(d[v], (blocks.TITLE, blocks._generic_imd_block, blocks._generic_gromos_block)) or issubclass(d[v].__class__, _general_gromos_file._general_gromos_file)): + if isinstance(d[v], (blocks.TITLE, blocks._generic_imd_block, blocks._generic_gromos_block)) or issubclass( + d[v].__class__, _general_gromos_file._general_gromos_file + ): d.update({v: vars(d[v])}) json.dump(d, open(out_path, "w")) diff --git a/pygromos/files/topology/disres.py b/pygromos/files/topology/disres.py index 6b4ca151..552066a3 100644 --- a/pygromos/files/topology/disres.py +++ b/pygromos/files/topology/disres.py @@ -6,14 +6,13 @@ class Distance_restraints(_general_gromos_file._general_gromos_file): required_blocks = ["TITLE", "DISTANCERESPEC"] - _gromos_file_ending:str = "disres" + _gromos_file_ending: str = "disres" - def __init__(self, in_value:(str or dict)=None): + def __init__(self, in_value: (str or dict) = None): self.blocksset = [] - self.block_names = {"TITLE": "title_block", "DISTANCERESSPEC":"distance_res_spec_block"} + self.block_names = {"TITLE": "title_block", "DISTANCERESSPEC": "distance_res_spec_block"} super().__init__(in_value=in_value) - """ if(type(path) is str): self.path = path @@ -24,14 +23,15 @@ def __init__(self, in_value:(str or dict)=None): else: raise IOError("disres class got "+str(type(path))+" as input. Unknown input type for disres.") """ + def read_blocks(self): - #parse file into dicts + # parse file into dicts data = parser.read_disres(self.path) - #add _blocks as attribute to objects + # add _blocks as attribute to objects for key, sub_content in data.items(): - #print(sub_content) + # print(sub_content) self.add_block(block=sub_content) class Disres(Distance_restraints): - pass \ No newline at end of file + pass diff --git a/pygromos/files/topology/ifp.py b/pygromos/files/topology/ifp.py index 82a158e2..010a1599 100644 --- a/pygromos/files/topology/ifp.py +++ b/pygromos/files/topology/ifp.py @@ -8,28 +8,29 @@ from pygromos.files._basics import _general_gromos_file, parser from typing import Union + class ifp(_general_gromos_file._general_gromos_file): _gromos_file_ending = "ifp" - def __init__(self, in_value:Union[str, dict]): + + def __init__(self, in_value: Union[str, dict]): super().__init__(in_value=in_value) def read_file(self): - #Read blocks to string + # Read blocks to string data = parser.read_general_gromos_file(self._orig_file_path) - #translate the string subblocks + # translate the string subblocks blocks = {} for block_title in data: - #print(block_title) - #print("\t", data[block_title]) + # print(block_title) + # print("\t", data[block_title]) self.add_block(blocktitle=block_title, content=data[block_title]) blocks.update({block_title: self.__getattribute__(block_title)}) return blocks - #for key, sub_content in data.items(): + # for key, sub_content in data.items(): # try: # self.add_block(blocktitle=key, content=sub_content) # except Exception as err: # #Here new block updates can be caugth # raise IOError("Could not read in imd " + key + " block!\n values: \n\t" + str(sub_content) + "\n\n" + "\n\t".join(err.args)) - diff --git a/pygromos/files/topology/mtb.py b/pygromos/files/topology/mtb.py index 9a644aab..6633225d 100644 --- a/pygromos/files/topology/mtb.py +++ b/pygromos/files/topology/mtb.py @@ -10,11 +10,12 @@ from pygromos.files._basics import _general_gromos_file from pygromos.files.blocks import mtb_blocks as blocks + class Mtb(_general_gromos_file._general_gromos_file): - _gromos_file_ending:str = "mtb" + _gromos_file_ending: str = "mtb" MTBUILDBLSOLUTE_list: List[blocks.MTBUILDBLSOLUTE] - def __init__(self, in_value:(str or dict or None), _future_file:bool=False): + def __init__(self, in_value: (str or dict or None), _future_file: bool = False): self.MTBUILDBLSOLUTE_list = [] super().__init__(in_value, _future_file) @@ -23,34 +24,33 @@ def __str__(self): for block in self.MTBUILDBLSOLUTE_list: ret_str += str(block) return ret_str - def read_file(self): - #Read blocks to string + # Read blocks to string data = self.read_mtb_file(self._orig_file_path) - #translate the string subblocks + # translate the string subblocks block_dict = {} for block_title, block_data in data: if block_title == "MTBUILDBLSOLUTE": - mtb_block = blocks.MTBUILDBLSOLUTE(content = block_data) + mtb_block = blocks.MTBUILDBLSOLUTE(content=block_data) self.MTBUILDBLSOLUTE_list.append(mtb_block) else: self.add_block(blocktitle=block_title, content=block_data) block_dict.update({block_title: self.__getattribute__(block_title)}) return block_dict - def read_mtb_file(self, path:str)->List: + def read_mtb_file(self, path: str) -> List: data = [] first_key = True key = "" block = [] - with open(path, 'r') as infile: + with open(path, "r") as infile: for line in infile: if first_key: - if(line.startswith("#")): + if line.startswith("#"): continue key = line.strip().upper() first_key = False @@ -61,4 +61,4 @@ def read_mtb_file(self, path:str)->List: else: block.append(line) infile.close() - return data \ No newline at end of file + return data diff --git a/pygromos/files/topology/ptp.py b/pygromos/files/topology/ptp.py index 6d21bc8e..30d08ceb 100644 --- a/pygromos/files/topology/ptp.py +++ b/pygromos/files/topology/ptp.py @@ -9,7 +9,9 @@ class Pertubation_topology(_general_gromos_file._general_gromos_file): _block_order = ["TITLE"] - required_blocks = ["TITLE", ] + required_blocks = [ + "TITLE", + ] TITLE: blocks.TITLE MPERATOM: blocks.MPERTATOM PERTATOMPARAM: blocks.PERTATOMPARAM @@ -19,24 +21,22 @@ class Pertubation_topology(_general_gromos_file._general_gromos_file): PERTBONDANGLEH: blocks.PERTBONDANGLEH PERTPROPERDIH: blocks.PERTPROPERDIH - _gromos_file_ending:str = "ptp" + _gromos_file_ending: str = "ptp" - def __init__(self, in_value:(str or dict)=None): + def __init__(self, in_value: (str or dict) = None): super().__init__(in_value=in_value) - #TODO: maybe somebody can make a better solution for this. This is a ugly fix to unify the structure of the blocks + # TODO: maybe somebody can make a better solution for this. This is a ugly fix to unify the structure of the blocks for block in sorted(self.get_block_names()): setattr(self, block, deepcopy(getattr(self, block))) - def read_blocks(self): - #parse file into dicts + # parse file into dicts data = parser.read_ptp(self.path) for key in data: self.add_block(block=data[key]) - class Ptp(Pertubation_topology): - pass \ No newline at end of file + pass diff --git a/pygromos/files/topology/top.py b/pygromos/files/topology/top.py index 6d535ad9..49396c4a 100644 --- a/pygromos/files/topology/top.py +++ b/pygromos/files/topology/top.py @@ -7,7 +7,7 @@ Author: Marc Lehner, Benjamin Ries """ -#imports +# imports from copy import deepcopy from typing import TypeVar, Union import warnings @@ -21,12 +21,12 @@ TopType = TypeVar("Top") -#functions +# functions def make_topolog(input_arg, build, param, seq, solve="H2O"): - #define python command - command="make_top "+input_arg+" "+param+" "+seq+" "+solve+" \n" + # define python command + command = "make_top " + input_arg + " " + param + " " + seq + " " + solve + " \n" - #execute command + # execute command try: bash.execute(command=command) except Exception as err: @@ -34,37 +34,40 @@ def make_topolog(input_arg, build, param, seq, solve="H2O"): return command + def combine_topologies(): - raise Exception('not implemented yet!') + raise Exception("not implemented yet!") + def check_top(): - raise Exception('not implemented yet!') + raise Exception("not implemented yet!") -#file Classes + +# file Classes class Top(_general_gromos_file._general_gromos_file): - _gromos_file_ending:str = "top" + _gromos_file_ending: str = "top" - def __init__(self, in_value:(str or dict or None or TopType), _future_file:bool=False): + def __init__(self, in_value: (str or dict or None or TopType), _future_file: bool = False): if type(in_value) is str: super().__init__(in_value=in_value, _future_file=_future_file) - elif(in_value == None): + elif in_value == None: self.path = "" self.block_names = {} super().__init__(in_value=None) - elif(type(in_value) is __class__): - raise Exception('not implemented yet!') + elif type(in_value) is __class__: + raise Exception("not implemented yet!") else: - raise Exception('not implemented yet!') + raise Exception("not implemented yet!") - def __add__(self, top:TopType)->TopType: + def __add__(self, top: TopType) -> TopType: return self._add_top(top=top) - def _add_top(self, top:Union[TopType, None], solvFrom1:bool=True, verbose:bool=False)->TopType: + def _add_top(self, top: Union[TopType, None], solvFrom1: bool = True, verbose: bool = False) -> TopType: """ - combines two topologies. Parameters are taken from the initial topology. + combines two topologies. Parameters are taken from the initial topology. But missing parameters from the second topology will be added. - Can be used like com_top from Gromos++ + Can be used like com_top from Gromos++ Parameters ---------- @@ -88,128 +91,144 @@ def _add_top(self, top:Union[TopType, None], solvFrom1:bool=True, verbose:bool=F return retTop # add solv if not solvFrom1: - if verbose: print("taking solvent from second topology") + if verbose: + print("taking solvent from second topology") retTop.SOLVENTATOM = top.SOLVENTATOM retTop.SOLVENTCONSTR = top.SOLVENTCONSTR - #calculate the shift of atom types of the second topology and add new atomtypes + # calculate the shift of atom types of the second topology and add new atomtypes atomTypeShift = {} - if not (hasattr(retTop, "ATOMTYPENAME") and len(retTop.ATOMTYPENAME.content)>=2): + if not (hasattr(retTop, "ATOMTYPENAME") and len(retTop.ATOMTYPENAME.content) >= 2): setattr(retTop, "ATOMTYPENAME", deepcopy(top.ATOMTYPENAME)) setattr(retTop, "LJPARAMETERS", deepcopy(top.LJPARAMETERS)) - for idx, atomT in enumerate(top.ATOMTYPENAME.content[1:]): #new atomtypes to find names for + for idx, atomT in enumerate(top.ATOMTYPENAME.content[1:]): # new atomtypes to find names for foundAtomType = False - for mainIdx, mainAtomT in enumerate(retTop.ATOMTYPENAME.content[1:]): #AtomTypes in self to match against - if atomT == mainAtomT: + for mainIdx, mainAtomT in enumerate(retTop.ATOMTYPENAME.content[1:]): # AtomTypes in self to match against + if atomT == mainAtomT: foundAtomType = True - atomTypeShift.update({idx+1:mainIdx+1}) + atomTypeShift.update({idx + 1: mainIdx + 1}) break if not foundAtomType: retTop.ATOMTYPENAME.content[0][0] = str(int(retTop.ATOMTYPENAME.content[0][0]) + 1) retTop.ATOMTYPENAME.content.append(atomT) - atomTypeShift.update({idx+1:retTop.ATOMTYPENAME.content[0][0]}) - ljType = top.get_LJparameter_from_IAC(IAC=idx+1) + atomTypeShift.update({idx + 1: retTop.ATOMTYPENAME.content[0][0]}) + ljType = top.get_LJparameter_from_IAC(IAC=idx + 1) retTop.add_new_LJparameter(C6=float(ljType.C6), C12=float(ljType.C12)) - if verbose: print("atomTypeShift: " + str(atomTypeShift)) + if verbose: + print("atomTypeShift: " + str(atomTypeShift)) - #add RESNAME + # add RESNAME for resname in top.RESNAME.content[1:]: retTop.add_new_resname(resname[0]) - #add SOLUTEATOM + # add SOLUTEATOM if hasattr(retTop, "SOLUTEATOM"): - atnmShift = retTop.SOLUTEATOM.content[-1].ATNM #Number of atoms found in main top. Shift secondary top atoms accordingly - mresShift = retTop.SOLUTEATOM.content[-1].MRES #Number of molecules found in main top. + atnmShift = retTop.SOLUTEATOM.content[ + -1 + ].ATNM # Number of atoms found in main top. Shift secondary top atoms accordingly + mresShift = retTop.SOLUTEATOM.content[-1].MRES # Number of molecules found in main top. else: - atnmShift=0 - mresShift=0 - if verbose: print("atom number shift: " + str(atnmShift)) - if verbose: print("molecule number shift: " + str(mresShift)) + atnmShift = 0 + mresShift = 0 + if verbose: + print("atom number shift: " + str(atnmShift)) + if verbose: + print("molecule number shift: " + str(mresShift)) for atom in top.SOLUTEATOM.content: - retTop.add_new_soluteatom(ATNM = atnmShift + atom.ATNM, - MRES = mresShift + atom.MRES, - PANM = atom.PANM, - IAC = atomTypeShift[atom.IAC], - MASS = atom.MASS, - CG = atom.CG, - CGC = atom.CGC, - INE = [x+atnmShift for x in atom.INEvalues], - INE14 = [x+atnmShift for x in atom.INE14values]) + retTop.add_new_soluteatom( + ATNM=atnmShift + atom.ATNM, + MRES=mresShift + atom.MRES, + PANM=atom.PANM, + IAC=atomTypeShift[atom.IAC], + MASS=atom.MASS, + CG=atom.CG, + CGC=atom.CGC, + INE=[x + atnmShift for x in atom.INEvalues], + INE14=[x + atnmShift for x in atom.INE14values], + ) # add bonds and bonds with H for bond in top.BOND.content: bondType = top.BONDSTRETCHTYPE.content[bond.ICB - 1] - retTop.add_new_bond(k=bondType.CHB, - b0=bondType.B0, - atomI=bond.IB + atnmShift, - atomJ=bond.JB + atnmShift) + retTop.add_new_bond(k=bondType.CHB, b0=bondType.B0, atomI=bond.IB + atnmShift, atomJ=bond.JB + atnmShift) for bond in top.BONDH.content: bondType = top.BONDSTRETCHTYPE.content[bond.ICB - 1] - retTop.add_new_bond(k=bondType.CHB, - b0=bondType.B0, - atomI=bond.IB + atnmShift, - atomJ=bond.JB + atnmShift, - includesH=True) + retTop.add_new_bond( + k=bondType.CHB, b0=bondType.B0, atomI=bond.IB + atnmShift, atomJ=bond.JB + atnmShift, includesH=True + ) # add angles and angles with H for angle in top.BONDANGLE.content: angleType = top.BONDANGLEBENDTYPE.content[angle.ICT - 1] - retTop.add_new_angle(k=angleType.CT, - kh=angleType.CHT, - b0=angleType.T0, - atomI=angle.IT + atnmShift, - atomJ=angle.JT + atnmShift, - atomK=angle.KT + atnmShift) + retTop.add_new_angle( + k=angleType.CT, + kh=angleType.CHT, + b0=angleType.T0, + atomI=angle.IT + atnmShift, + atomJ=angle.JT + atnmShift, + atomK=angle.KT + atnmShift, + ) for angle in top.BONDANGLEH.content: angleType = top.BONDANGLEBENDTYPE.content[angle.ICT - 1] - retTop.add_new_angle(k=angleType.CT, - kh=angleType.CHT, - b0=angleType.T0, - atomI=angle.IT + atnmShift, - atomJ=angle.JT + atnmShift, - atomK=angle.KT + atnmShift, includesH=True) + retTop.add_new_angle( + k=angleType.CT, + kh=angleType.CHT, + b0=angleType.T0, + atomI=angle.IT + atnmShift, + atomJ=angle.JT + atnmShift, + atomK=angle.KT + atnmShift, + includesH=True, + ) # add diheadrals and diheadrals with H for dihdrl in top.DIHEDRAL.content: dihdrlType = top.TORSDIHEDRALTYPE.content[dihdrl.ICP - 1] - retTop.add_new_torsiondihedral(CP=dihdrlType.CP, - PD=dihdrlType.PD, - NP=dihdrlType.NP, - atomI=dihdrl.IP + atnmShift, - atomJ=dihdrl.JP + atnmShift, - atomK=dihdrl.KP + atnmShift, - atomL=dihdrl.LP + atnmShift) + retTop.add_new_torsiondihedral( + CP=dihdrlType.CP, + PD=dihdrlType.PD, + NP=dihdrlType.NP, + atomI=dihdrl.IP + atnmShift, + atomJ=dihdrl.JP + atnmShift, + atomK=dihdrl.KP + atnmShift, + atomL=dihdrl.LP + atnmShift, + ) for dihdrl in top.DIHEDRALH.content: dihdrlType = top.TORSDIHEDRALTYPE.content[dihdrl.ICPH - 1] - retTop.add_new_torsiondihedral(CP=dihdrlType.CP, - PD=dihdrlType.PD, - NP=dihdrlType.NP, - atomI=dihdrl.IPH + atnmShift, - atomJ=dihdrl.JPH + atnmShift, - atomK=dihdrl.KPH + atnmShift, - atomL=dihdrl.LPH + atnmShift, - includesH=True) + retTop.add_new_torsiondihedral( + CP=dihdrlType.CP, + PD=dihdrlType.PD, + NP=dihdrlType.NP, + atomI=dihdrl.IPH + atnmShift, + atomJ=dihdrl.JPH + atnmShift, + atomK=dihdrl.KPH + atnmShift, + atomL=dihdrl.LPH + atnmShift, + includesH=True, + ) # add impdihedrals with and without H for dihdrl in top.IMPDIHEDRAL.content: dihdrlType = top.IMPDIHEDRALTYPE.content[dihdrl.ICQ - 1] - retTop.add_new_impdihedral(CQ=dihdrlType.CQ, - Q0=dihdrlType.Q0, - atomI=dihdrl.IQ + atnmShift, - atomJ=dihdrl.JQ + atnmShift, - atomK=dihdrl.KQ + atnmShift, - atomL=dihdrl.LQ + atnmShift) + retTop.add_new_impdihedral( + CQ=dihdrlType.CQ, + Q0=dihdrlType.Q0, + atomI=dihdrl.IQ + atnmShift, + atomJ=dihdrl.JQ + atnmShift, + atomK=dihdrl.KQ + atnmShift, + atomL=dihdrl.LQ + atnmShift, + ) for dihdrl in top.IMPDIHEDRALH.content: dihdrlType = top.IMPDIHEDRALTYPE.content[dihdrl.ICQH - 1] - retTop.add_new_impdihedral(CQ=dihdrlType.CQ, - Q0=dihdrlType.Q0, - atomI=dihdrl.IQH + atnmShift, - atomJ=dihdrl.JQH + atnmShift, - atomK=dihdrl.KQH + atnmShift, - atomL=dihdrl.LQH + atnmShift, - includesH=True) + retTop.add_new_impdihedral( + CQ=dihdrlType.CQ, + Q0=dihdrlType.Q0, + atomI=dihdrl.IQH + atnmShift, + atomJ=dihdrl.JQH + atnmShift, + atomK=dihdrl.KQH + atnmShift, + atomL=dihdrl.LQH + atnmShift, + includesH=True, + ) # add SOLUTEMOLECULES for solmol in top.SOLUTEMOLECULES.content[1:]: @@ -225,10 +244,10 @@ def _add_top(self, top:Union[TopType, None], solvFrom1:bool=True, verbose:bool=F return retTop - def __mul__(self, n_multiplication:int): + def __mul__(self, n_multiplication: int): return self.multiply_top(n_multiplication) - - def multiply_top(self, n_muliplication:int, unifyGroups:bool = False, verbose=False)->TopType: + + def multiply_top(self, n_muliplication: int, unifyGroups: bool = False, verbose=False) -> TopType: # catch simple cases and create return top if n_muliplication == 0: @@ -237,24 +256,24 @@ def multiply_top(self, n_muliplication:int, unifyGroups:bool = False, verbose=Fa if n_muliplication == 1: return retTop - top = deepcopy(self) # for safe storage and reagsinment so that we can modifie + top = deepcopy(self) # for safe storage and reagsinment so that we can modifie - n_loops = n_muliplication - 1 # -1 since first one is a deepcopy - atnmShift = 0 # init for number of atoms. Will be determined in SOLUTEATOM - mresShift = 0 # init for number of molecules. Will be determined in SOLUTEMOLECULES + n_loops = n_muliplication - 1 # -1 since first one is a deepcopy + atnmShift = 0 # init for number of atoms. Will be determined in SOLUTEATOM + mresShift = 0 # init for number of molecules. Will be determined in SOLUTEMOLECULES ##start with additonal copies of all Blocks - #multiply RESNAME + # multiply RESNAME if hasattr(top, "RESNAME") and len(top.RESNAME.content) > 0: retTop.RESNAME.content[0][0] = str(int(top.RESNAME.content[0][0]) * n_muliplication) for _ in range(n_loops): retTop.RESNAME.content.extend(top.RESNAME.content[1:]) - #multiply SOLUTEATOM + # multiply SOLUTEATOM if hasattr(top, "SOLUTEATOM") and len(top.SOLUTEATOM.content) > 0: - atnmShift = top.SOLUTEATOM.content[-1].ATNM #Number of atoms found in top - mresShift = top.SOLUTEATOM.content[-1].MRES #Number of molecules found in top. + atnmShift = top.SOLUTEATOM.content[-1].ATNM # Number of atoms found in top + mresShift = top.SOLUTEATOM.content[-1].MRES # Number of molecules found in top. if verbose: print("atnmShift:", atnmShift) @@ -266,11 +285,11 @@ def multiply_top(self, n_muliplication:int, unifyGroups:bool = False, verbose=Fa for atom in top.SOLUTEATOM.content: atom.ATNM += atnmShift atom.MRES += mresShift - atom.INEvalues = [i+atnmShift for i in atom.INEvalues] #TODO remove str/int conversion - atom.INE14values = [i+atnmShift for i in atom.INE14values] + atom.INEvalues = [i + atnmShift for i in atom.INEvalues] # TODO remove str/int conversion + atom.INE14values = [i + atnmShift for i in atom.INE14values] retTop.SOLUTEATOM.content.append(deepcopy(atom)) - #multiply Bonds(H) + # multiply Bonds(H) if hasattr(top, "BOND") and len(top.BOND.content) > 0: retTop.BOND.NBON *= n_muliplication for i in range(n_loops): @@ -285,8 +304,8 @@ def multiply_top(self, n_muliplication:int, unifyGroups:bool = False, verbose=Fa bond.IB += atnmShift bond.JB += atnmShift retTop.BONDH.content.append(deepcopy(bond)) - - #multiply Angles(H) + + # multiply Angles(H) if hasattr(top, "BONDANGLE") and len(top.BONDANGLE.content) > 0: retTop.BONDANGLE.NTHE *= n_muliplication for i in range(n_loops): @@ -302,9 +321,9 @@ def multiply_top(self, n_muliplication:int, unifyGroups:bool = False, verbose=Fa angle.IT += atnmShift angle.JT += atnmShift angle.KT += atnmShift - retTop.BONDANGLEH.content.append(deepcopy(angle)) + retTop.BONDANGLEH.content.append(deepcopy(angle)) - #multiply Impdihedrals(H) + # multiply Impdihedrals(H) if hasattr(top, "IMPDIHEDRAL") and len(top.IMPDIHEDRAL.content) > 0: retTop.IMPDIHEDRAL.NQHI *= n_muliplication for i in range(n_loops): @@ -324,7 +343,7 @@ def multiply_top(self, n_muliplication:int, unifyGroups:bool = False, verbose=Fa angle.LQH += atnmShift retTop.IMPDIHEDRALH.content.append(deepcopy(angle)) - #multiply Torsions(H) + # multiply Torsions(H) if hasattr(top, "DIHEDRAL") and len(top.DIHEDRAL.content) > 0: retTop.DIHEDRAL.NPHI *= n_muliplication for i in range(n_loops): @@ -344,57 +363,83 @@ def multiply_top(self, n_muliplication:int, unifyGroups:bool = False, verbose=Fa angle.LPH += atnmShift retTop.DIHEDRALH.content.append(deepcopy(angle)) - if hasattr(top, "SOLUTEMOLECULES"): - if unifyGroups and int(top.SOLUTEMOLECULES.content[0][0])==1: + if unifyGroups and int(top.SOLUTEMOLECULES.content[0][0]) == 1: retTop.SOLUTEMOLECULES.content[1][0] = str(int(retTop.SOLUTEMOLECULES.content[1][0]) * n_muliplication) else: retTop.SOLUTEMOLECULES.content[0][0] = str(int(top.SOLUTEMOLECULES.content[0][0]) * n_muliplication) for i in range(n_loops): - groups = [str(int(i)+atnmShift) for i in top.SOLUTEMOLECULES.content[1]] + groups = [str(int(i) + atnmShift) for i in top.SOLUTEMOLECULES.content[1]] retTop.SOLUTEMOLECULES.content.append(groups) if hasattr(top, "TEMPERATUREGROUPS"): - if unifyGroups and int(top.TEMPERATUREGROUPS.content[0][0])==1: - retTop.TEMPERATUREGROUPS.content[1][0] = str(int(retTop.TEMPERATUREGROUPS.content[1][0]) * n_muliplication) + if unifyGroups and int(top.TEMPERATUREGROUPS.content[0][0]) == 1: + retTop.TEMPERATUREGROUPS.content[1][0] = str( + int(retTop.TEMPERATUREGROUPS.content[1][0]) * n_muliplication + ) else: retTop.TEMPERATUREGROUPS.content[0][0] = str(int(top.TEMPERATUREGROUPS.content[0][0]) * n_muliplication) for i in range(n_loops): - groups = [str(int(i)+atnmShift) for i in top.TEMPERATUREGROUPS.content[1]] + groups = [str(int(i) + atnmShift) for i in top.TEMPERATUREGROUPS.content[1]] retTop.TEMPERATUREGROUPS.content.append(groups) if hasattr(top, "PRESSUREGROUPS"): - if unifyGroups and int(top.PRESSUREGROUPS.content[0][0])==1: + if unifyGroups and int(top.PRESSUREGROUPS.content[0][0]) == 1: retTop.PRESSUREGROUPS.content[1][0] = str(int(retTop.PRESSUREGROUPS.content[1][0]) * n_muliplication) else: retTop.PRESSUREGROUPS.content[0][0] = str(int(top.PRESSUREGROUPS.content[0][0]) * n_muliplication) for i in range(n_loops): - groups = [str(int(i)+atnmShift) for i in top.PRESSUREGROUPS.content[1]] + groups = [str(int(i) + atnmShift) for i in top.PRESSUREGROUPS.content[1]] retTop.PRESSUREGROUPS.content.append(groups) - - # return everything return retTop - def read_file(self): - #Read blocks to string + # Read blocks to string data = parser.read_general_gromos_file(self._orig_file_path) - #translate the string subblocks + # translate the string subblocks blocks = {} for block_title in data: - #print(block_title) + # print(block_title) self.add_block(blocktitle=block_title, content=data[block_title]) blocks.update({block_title: self.__getattribute__(block_title)}) return blocks - def make_ordered(self, orderList:list=None): + def make_ordered(self, orderList: list = None): if orderList: self._block_order = orderList else: - self._block_order = ["TITLE", "PHYSICALCONSTANTS","TOPVERSION","ATOMTYPENAME","RESNAME","SOLUTEATOM","BONDSTRETCHTYPE","BONDH","BOND","BONDANGLEBENDTYPE","BONDANGLEH","BONDANGLE","IMPDIHEDRALTYPE","IMPDIHEDRALH","IMPDIHEDRAL","TORSDIHEDRALTYPE","DIHEDRALH","DIHEDRAL","CROSSDIHEDRALH","CROSSDIHEDRAL","LJPARAMETERS","SOLUTEMOLECULES","TEMPERATUREGROUPS","PRESSUREGROUPS","LJEXCEPTIONS","SOLVENTATOM","SOLVENTCONSTR"] + self._block_order = [ + "TITLE", + "PHYSICALCONSTANTS", + "TOPVERSION", + "ATOMTYPENAME", + "RESNAME", + "SOLUTEATOM", + "BONDSTRETCHTYPE", + "BONDH", + "BOND", + "BONDANGLEBENDTYPE", + "BONDANGLEH", + "BONDANGLE", + "IMPDIHEDRALTYPE", + "IMPDIHEDRALH", + "IMPDIHEDRAL", + "TORSDIHEDRALTYPE", + "DIHEDRALH", + "DIHEDRAL", + "CROSSDIHEDRALH", + "CROSSDIHEDRAL", + "LJPARAMETERS", + "SOLUTEMOLECULES", + "TEMPERATUREGROUPS", + "PRESSUREGROUPS", + "LJEXCEPTIONS", + "SOLVENTATOM", + "SOLVENTCONSTR", + ] def get_num_atomtypes(self) -> int: if not hasattr(self, "ATOMTYPENAME"): @@ -402,31 +447,43 @@ def get_num_atomtypes(self) -> int: else: return int(self.ATOMTYPENAME.content[0][0]) - def add_new_atomtype(self, name:str, verbose=False): + def add_new_atomtype(self, name: str, verbose=False): if not hasattr(self, "ATOMTYPENAME"): - defaultContent=['0', 'Dummy'] + defaultContent = ["0", "Dummy"] self.add_block(blocktitle="ATOMTYPENAME", content=defaultContent, verbose=verbose) self.ATOMTYPENAME.content.append([name]) - self.ATOMTYPENAME.content.remove(['Dummy']) + self.ATOMTYPENAME.content.remove(["Dummy"]) else: if len(self.ATOMTYPENAME.content) < 1: self.ATOMTYPENAME.content.append(["0"]) self.ATOMTYPENAME.content.append([name]) - self.ATOMTYPENAME.content[0][0] = str(int(self.ATOMTYPENAME.content[0][0])+1) + self.ATOMTYPENAME.content[0][0] = str(int(self.ATOMTYPENAME.content[0][0]) + 1) - def add_new_resname(self, name:str, verbose=False): + def add_new_resname(self, name: str, verbose=False): if not hasattr(self, "RESNAME"): - defaultContent=['0', 'Dummy'] + defaultContent = ["0", "Dummy"] self.add_block(blocktitle="RESNAME", content=defaultContent, verbose=verbose) self.RESNAME.content.append([name]) - self.RESNAME.content.remove(['Dummy']) + self.RESNAME.content.remove(["Dummy"]) else: if len(self.RESNAME.content) < 1: self.RESNAME.content.append(["0"]) self.RESNAME.content.append([name]) - self.RESNAME.content[0][0] = str(int(self.RESNAME.content[0][0])+1) - - def add_new_soluteatom(self, ATNM:int=0, MRES:int=0, PANM:str="", IAC:int=0, MASS:float=0, CG:float=0, CGC:int=0, INE:list=[], INE14:list=[], verbose=False): + self.RESNAME.content[0][0] = str(int(self.RESNAME.content[0][0]) + 1) + + def add_new_soluteatom( + self, + ATNM: int = 0, + MRES: int = 0, + PANM: str = "", + IAC: int = 0, + MASS: float = 0, + CG: float = 0, + CGC: int = 0, + INE: list = [], + INE14: list = [], + verbose=False, + ): if not hasattr(self, "SOLUTEATOM"): self.add_block(blocktitle="SOLUTEATOM", content=[], verbose=verbose) self.SOLUTEATOM.NRP = 0 @@ -438,14 +495,25 @@ def add_new_soluteatom(self, ATNM:int=0, MRES:int=0, PANM:str="", IAC:int=0, MAS MRES = self.SOLUTEATOM.content[-1].MRES + 1 else: MRES = 1 - #create new entry - entry = blocks.soluteatom_type(ATNM=ATNM, MRES=MRES, PANM=PANM, IAC=IAC, MASS=MASS, CG=CG, CGC=CGC, INE=len(INE), INEvalues=INE, INE14=len(INE14), INE14values=INE14) + # create new entry + entry = blocks.soluteatom_type( + ATNM=ATNM, + MRES=MRES, + PANM=PANM, + IAC=IAC, + MASS=MASS, + CG=CG, + CGC=CGC, + INE=len(INE), + INEvalues=INE, + INE14=len(INE14), + INE14values=INE14, + ) self.SOLUTEATOM.content.append(entry) self.SOLUTEATOM.NRP += 1 - - def add_new_bond(self, k:float, b0:float, atomI:int, atomJ:int, includesH:bool = False, verbose=False): - #check if all classes are ready, if not create + def add_new_bond(self, k: float, b0: float, atomI: int, atomJ: int, includesH: bool = False, verbose=False): + # check if all classes are ready, if not create if not hasattr(self, "BONDSTRETCHTYPE"): self.add_block(blocktitle="BONDSTRETCHTYPE", content=list(), verbose=verbose) if includesH: @@ -454,13 +522,12 @@ def add_new_bond(self, k:float, b0:float, atomI:int, atomJ:int, includesH:bool = else: if not hasattr(self, "BOND"): self.add_block(blocktitle="BOND", content=list(), verbose=verbose) - - + # find the bondstretchtype number or create new bondstretchtype # TODO: add quartic force (CB) bond_type_number = 0 iterator = 1 - quartic = k/(2*(b0**2)) + quartic = k / (2 * (b0**2)) newBondStretchType = blocks.bondstretchtype_type(CB=quartic, CHB=k, B0=b0) for bond_type in self.BONDSTRETCHTYPE.content: if bond_type.CHB == newBondStretchType.CHB and bond_type.B0 == newBondStretchType.B0: @@ -468,14 +535,14 @@ def add_new_bond(self, k:float, b0:float, atomI:int, atomJ:int, includesH:bool = else: iterator += 1 bond_type_number = iterator - if iterator > len(self.BONDSTRETCHTYPE.content):#bond type was not found -> add new bondtype + if iterator > len(self.BONDSTRETCHTYPE.content): # bond type was not found -> add new bondtype self.BONDSTRETCHTYPE.content.append(newBondStretchType) self.BONDSTRETCHTYPE.NBTY += 1 - #create new bond TODO: maybe check if already exists. But I will asume smart users + # create new bond TODO: maybe check if already exists. But I will asume smart users newBond = blocks.top_bond_type(IB=atomI, JB=atomJ, ICB=bond_type_number) - #check if we are adding a bond to BOND or BONDH + # check if we are adding a bond to BOND or BONDH if includesH: self.BONDH.content.append(newBond) self.BONDH.NBONH += 1 @@ -483,8 +550,19 @@ def add_new_bond(self, k:float, b0:float, atomI:int, atomJ:int, includesH:bool = self.BOND.content.append(newBond) self.BOND.NBON += 1 - def add_new_angle(self, k:float, kh:float, b0:float, atomI:int, atomJ:int, atomK:int, includesH:bool = False, verbose=False, convertToQuartic=False): - #check if all classes are ready, if not create + def add_new_angle( + self, + k: float, + kh: float, + b0: float, + atomI: int, + atomJ: int, + atomK: int, + includesH: bool = False, + verbose=False, + convertToQuartic=False, + ): + # check if all classes are ready, if not create if not hasattr(self, "BONDANGLEBENDTYPE"): self.add_block(blocktitle="BONDANGLEBENDTYPE", content=[], verbose=verbose) if includesH: @@ -493,7 +571,7 @@ def add_new_angle(self, k:float, kh:float, b0:float, atomI:int, atomJ:int, atomK else: if not hasattr(self, "BONDANGLE"): self.add_block(blocktitle="BONDANGLE", content=[], verbose=verbose) - + # find the BONDANGLEBENDTYPE number or create new BONDANGLEBENDTYPE # TODO: add harmonic in the angle cosine force (CT) angle_type_number = 0 @@ -506,14 +584,14 @@ def add_new_angle(self, k:float, kh:float, b0:float, atomI:int, atomJ:int, atomK else: iterator += 1 angle_type_number = iterator - if iterator > len(self.BONDANGLEBENDTYPE.content):#angle type was not found -> add new bondtype + if iterator > len(self.BONDANGLEBENDTYPE.content): # angle type was not found -> add new bondtype newBONDANGLEBENDTYPE = blocks.bondanglebendtype_type(CT=k, CHT=kh, T0=b0) self.BONDANGLEBENDTYPE.content.append(newBONDANGLEBENDTYPE) self.BONDANGLEBENDTYPE.NBTY += 1 - - #create new angle TODO: maybe check if already exists. But I will asume smart users + + # create new angle TODO: maybe check if already exists. But I will asume smart users newAngle = blocks.bondangle_type(IT=atomI, JT=atomJ, KT=atomK, ICT=angle_type_number) - #check if we are adding a bond to BONDANGLE or BONDANGLEH + # check if we are adding a bond to BONDANGLE or BONDANGLEH if includesH: self.BONDANGLEH.content.append(newAngle) self.BONDANGLEH.NTHEH += 1 @@ -538,16 +616,27 @@ def harmonic2quarticAngleConversion(self, kh, b0): """ # This conversion is taken from GROMOS manual II 18.1. Conversion of force constants - b0rad = b0*math.pi/180 #b0 in radians - kbT = 2.494323 #k boltzman * Temperature in kJ/mol + b0rad = b0 * math.pi / 180 # b0 in radians + kbT = 2.494323 # k boltzman * Temperature in kJ/mol # cosine is radian, but harmonic force constant is in degree -> first cos inside has to be calculated in degree - term1 = (math.cos((b0 + math.sqrt((kbT/kh)))*math.pi/180) - math.cos(b0rad))**2 - term2 = (math.cos((b0 - math.sqrt((kbT/kh)))*math.pi/180) - math.cos(b0rad))**2 - return 2*kbT/(term1 + term2) - - def add_new_torsiondihedral(self, CP:float, PD:float, NP:int, atomI:int, atomJ:int, atomK:int, atomL:int, includesH:bool = False, verbose=False): - #check if all classes are ready, if not create + term1 = (math.cos((b0 + math.sqrt((kbT / kh))) * math.pi / 180) - math.cos(b0rad)) ** 2 + term2 = (math.cos((b0 - math.sqrt((kbT / kh))) * math.pi / 180) - math.cos(b0rad)) ** 2 + return 2 * kbT / (term1 + term2) + + def add_new_torsiondihedral( + self, + CP: float, + PD: float, + NP: int, + atomI: int, + atomJ: int, + atomK: int, + atomL: int, + includesH: bool = False, + verbose=False, + ): + # check if all classes are ready, if not create if not hasattr(self, "TORSDIHEDRALTYPE"): self.add_block(blocktitle="TORSDIHEDRALTYPE", content=[], verbose=verbose) if includesH: @@ -556,7 +645,7 @@ def add_new_torsiondihedral(self, CP:float, PD:float, NP:int, atomI:int, atomJ:i else: if not hasattr(self, "DIHEDRAL"): self.add_block(blocktitle="DIHEDRAL", content=[], verbose=verbose) - + # find the TORSDIHEDRALTYPE number or create new TORSDIHEDRALTYPE torsion_type_number = 0 iterator = 1 @@ -565,32 +654,44 @@ def add_new_torsiondihedral(self, CP:float, PD:float, NP:int, atomI:int, atomJ:i break else: iterator += 1 - torsion_type_number = iterator #found the torsion - if iterator > len(self.TORSDIHEDRALTYPE.content):#torsion type was not found -> add new bondtype + torsion_type_number = iterator # found the torsion + if iterator > len(self.TORSDIHEDRALTYPE.content): # torsion type was not found -> add new bondtype newTORSDIHEDRALTYPE = blocks.torsdihedraltype_type(CP=CP, PD=PD, NP=NP) self.TORSDIHEDRALTYPE.content.append(newTORSDIHEDRALTYPE) self.TORSDIHEDRALTYPE.NPTY += 1 - - #check if we are adding a bond to DIHEDRAL or DIHEDRALH + + # check if we are adding a bond to DIHEDRAL or DIHEDRALH if includesH: - self.DIHEDRALH.content.append(blocks.dihedralh_type(IPH=atomI, JPH=atomJ, KPH=atomK, LPH=atomL, ICPH=torsion_type_number)) + self.DIHEDRALH.content.append( + blocks.dihedralh_type(IPH=atomI, JPH=atomJ, KPH=atomK, LPH=atomL, ICPH=torsion_type_number) + ) self.DIHEDRALH.NPHIH += 1 else: - self.DIHEDRAL.content.append(blocks.top_dihedral_type(IP=atomI, JP=atomJ, KP=atomK, LP=atomL, ICP=torsion_type_number)) + self.DIHEDRAL.content.append( + blocks.top_dihedral_type(IP=atomI, JP=atomJ, KP=atomK, LP=atomL, ICP=torsion_type_number) + ) self.DIHEDRAL.NPHI += 1 - - def add_new_impdihedral_type(self, CQ:float, Q0:float, verbose=False): - #check if all classes are ready, if not create + def add_new_impdihedral_type(self, CQ: float, Q0: float, verbose=False): + # check if all classes are ready, if not create if not hasattr(self, "IMPDIHEDRALTYPE"): self.add_block(blocktitle="IMPDIHEDRALTYPE", content=[], verbose=verbose) newIMPDIHEDRALTYPE = blocks.impdihedraltype_type(CQ=CQ, Q0=Q0) self.IMPDIHEDRALTYPE.content.append(newIMPDIHEDRALTYPE) self.IMPDIHEDRALTYPE.NQTY += 1 - - def add_new_impdihedral(self, CQ:float, Q0:float, atomI:int, atomJ:int, atomK:int, atomL:int, includesH:bool = False, verbose=False): - #check if all classes are ready, if not create + def add_new_impdihedral( + self, + CQ: float, + Q0: float, + atomI: int, + atomJ: int, + atomK: int, + atomL: int, + includesH: bool = False, + verbose=False, + ): + # check if all classes are ready, if not create if not hasattr(self, "IMPDIHEDRALTYPE"): self.add_block(blocktitle="IMPDIHEDRALTYPE", content=[], verbose=verbose) if includesH: @@ -599,7 +700,7 @@ def add_new_impdihedral(self, CQ:float, Q0:float, atomI:int, atomJ:int, atomK:in else: if not hasattr(self, "IMPDIHEDRAL"): self.add_block(blocktitle="IMPDIHEDRAL", content=[], verbose=verbose) - + # find the IMPDIHEDRALTYPE number or create new IMPDIHEDRALTYPE impdihedral_type_number = 1 iterator = 1 @@ -608,28 +709,41 @@ def add_new_impdihedral(self, CQ:float, Q0:float, atomI:int, atomJ:int, atomK:in break else: iterator += 1 - impdihedral_type_number = iterator #found the torsion - if iterator > len(self.IMPDIHEDRALTYPE.content):#torsion type was not found -> add new bondtype + impdihedral_type_number = iterator # found the torsion + if iterator > len(self.IMPDIHEDRALTYPE.content): # torsion type was not found -> add new bondtype self.add_new_impdihedral_type(CQ=CQ, Q0=Q0) - - #check if we are adding a bond to IMPDIHEDRALH or IMPDIHEDRALH + + # check if we are adding a bond to IMPDIHEDRALH or IMPDIHEDRALH if includesH: - self.IMPDIHEDRALH.content.append(blocks.impdihedralh_type(IQH=atomI, JQH=atomJ, KQH=atomK, LQH=atomL, ICQH=impdihedral_type_number)) + self.IMPDIHEDRALH.content.append( + blocks.impdihedralh_type(IQH=atomI, JQH=atomJ, KQH=atomK, LQH=atomL, ICQH=impdihedral_type_number) + ) self.IMPDIHEDRALH.NQHIH += 1 else: - self.IMPDIHEDRAL.content.append(blocks.impdihedral_type(IQ=atomI, JQ=atomJ, KQ=atomK, LQ=atomL, ICQ=impdihedral_type_number)) + self.IMPDIHEDRAL.content.append( + blocks.impdihedral_type(IQ=atomI, JQ=atomJ, KQ=atomK, LQ=atomL, ICQ=impdihedral_type_number) + ) self.IMPDIHEDRAL.NQHI += 1 - - #TODO: add implementation + # TODO: add implementation def add_new_crossdihedral(self, verbose=False): raise NotImplementedError("Who needs this???? Could you plox implement it. UwU") - def add_new_LJparameter(self, C6:float, C12:float, CS6:float=0, CS12:float=0, combination_rule:str="geometric", verbose=False, AddATOMTYPENAME:str=None, lowerBound:float=1e-100): + def add_new_LJparameter( + self, + C6: float, + C12: float, + CS6: float = 0, + CS12: float = 0, + combination_rule: str = "geometric", + verbose=False, + AddATOMTYPENAME: str = None, + lowerBound: float = 1e-100, + ): if not hasattr(self, "LJPARAMETERS"): self.add_block(blocktitle="LJPARAMETERS", content=[], verbose=verbose) self.LJPARAMETERS.NRATT2 = 0 - #safety + # safety if C6 < lowerBound: C6 = lowerBound if C12 < lowerBound: @@ -639,8 +753,8 @@ def add_new_LJparameter(self, C6:float, C12:float, CS6:float=0, CS12:float=0, co if CS12 < lowerBound: CS12 = lowerBound # add LJ parameter for all existing combinations - num=0 - nratt=int((math.sqrt(8*self.LJPARAMETERS.NRATT2+1)-1)/2) + num = 0 + nratt = int((math.sqrt(8 * self.LJPARAMETERS.NRATT2 + 1) - 1) / 2) for i in range(nratt): if combination_rule == "geometric": c6 = math.sqrt(float(C6 * self.LJPARAMETERS.content[num].C6)) @@ -649,24 +763,23 @@ def add_new_LJparameter(self, C6:float, C12:float, CS6:float=0, CS12:float=0, co cs12 = math.sqrt(float(CS12 * self.LJPARAMETERS.content[num].CS12)) else: raise NotImplementedError("Error in add_new_LJparameter: desired combination rule not implemented") - add = blocks.ljparameters_type(IAC=i+1, JAC=nratt+1, C6=c6, C12=c12, CS12=cs12, CS6=cs6) + add = blocks.ljparameters_type(IAC=i + 1, JAC=nratt + 1, C6=c6, C12=c12, CS12=cs12, CS6=cs6) self.LJPARAMETERS.append(add) - num += i+2 - #add new LJ paramter to self - add = blocks.ljparameters_type(IAC=nratt+1, JAC=nratt+1, C6=C6, C12=C12, CS12=CS12, CS6=CS6) + num += i + 2 + # add new LJ paramter to self + add = blocks.ljparameters_type(IAC=nratt + 1, JAC=nratt + 1, C6=C6, C12=C12, CS12=CS12, CS6=CS6) self.LJPARAMETERS.append(add) self.LJPARAMETERS.NRATT2 += nratt + 1 - + if AddATOMTYPENAME != None: if not hasattr(self, "ATOMTYPENAME"): self.add_block(blocktitle="ATOMTYPENAME", content=[], verbose=verbose) self.LJPARAMETERS.NRATT = 0 self.add_new_atomtype(AddATOMTYPENAME) - if(int(self.ATOMTYPENAME.content[0][0]) != self.LJPARAMETERS.content[-1].IAC): + if int(self.ATOMTYPENAME.content[0][0]) != self.LJPARAMETERS.content[-1].IAC: raise IndexError("Missmatch between number of ATOMTYPNAMEs and LJPARAMETERS") - - def find_LJparameterNumber(self, C12:float, C6:float) -> int: + def find_LJparameterNumber(self, C12: float, C6: float) -> int: if not hasattr(self, "LJPARAMETERS"): return 0 elif self.LJPARAMETERS.NRATT2 < 1: @@ -675,35 +788,56 @@ def find_LJparameterNumber(self, C12:float, C6:float) -> int: for lj in self.LJPARAMETERS.content: if C12 == lj.C12 and C6 == lj.C6: return lj.IAC - return 0 # LJ parameter not found + return 0 # LJ parameter not found - def get_LJparameter_from_IAC(self, IAC:int): + def get_LJparameter_from_IAC(self, IAC: int): if not hasattr(self, "LJPARAMETERS"): raise Exception("no LJPARAMETERS block to search in") if (IAC**2 - 1) > self.LJPARAMETERS.NRATT2: raise Exception("IAC key is too larger than IACs in LJ block") - return self.LJPARAMETERS.content[(IAC**2 -1)] - - - def add_new_atom(self, ATNM:int=0, MRES:int=0, PANM:str='_', IAC:int=1, MASS:float=1.0, CG:int=0, CGC:int=1, INE:list=[], INE14:list=[], verbose=False, C6:float=None, C12:float=None, CS6:float=0, CS12:float=0, IACname:str=None): + return self.LJPARAMETERS.content[(IAC**2 - 1)] + + def add_new_atom( + self, + ATNM: int = 0, + MRES: int = 0, + PANM: str = "_", + IAC: int = 1, + MASS: float = 1.0, + CG: int = 0, + CGC: int = 1, + INE: list = [], + INE14: list = [], + verbose=False, + C6: float = None, + C12: float = None, + CS6: float = 0, + CS12: float = 0, + IACname: str = None, + ): if IACname is None: IACname = PANM - + # Find IAC and (if needed) add a new LJ Parameter - if C6 != None or C12 != None: #need to find PANM and IAC + if C6 != None or C12 != None: # need to find PANM and IAC if hasattr(self, "LJPARAMETERS"): IAC = self.find_LJparameterNumber(C6=C6, C12=C12) - if IAC == 0: #IAC not found -> add new LJ parameter - self.add_new_LJparameter(C6=C6, C12=C12, CS6=CS6, CS12=CS12, verbose=verbose, AddATOMTYPENAME=IACname) + if IAC == 0: # IAC not found -> add new LJ parameter + self.add_new_LJparameter( + C6=C6, C12=C12, CS6=CS6, CS12=CS12, verbose=verbose, AddATOMTYPENAME=IACname + ) IAC = self.LJPARAMETERS.content[-1].IAC - if verbose: print("New Atomtype with LJ parameters added. IAC found as: " + str(IAC)) + if verbose: + print("New Atomtype with LJ parameters added. IAC found as: " + str(IAC)) else: self.add_new_LJparameter(C6=C6, C12=C12, CS6=CS6, CS12=CS12, verbose=verbose, AddATOMTYPENAME=IACname) IAC = 1 - self.add_new_soluteatom(ATNM=ATNM, MRES=MRES, PANM=PANM, IAC=IAC, MASS=MASS, CG=CG, CGC=CGC, INE=INE, INE14=INE14) + self.add_new_soluteatom( + ATNM=ATNM, MRES=MRES, PANM=PANM, IAC=IAC, MASS=MASS, CG=CG, CGC=CGC, INE=INE, INE14=INE14 + ) - def add_new_CONSTRAINT(self, IC:int, JC:int, ICC:float, verbose=False): + def add_new_CONSTRAINT(self, IC: int, JC: int, ICC: float, verbose=False): """ adds a CONSTRAINT entry to the topology @@ -714,7 +848,7 @@ def add_new_CONSTRAINT(self, IC:int, JC:int, ICC:float, verbose=False): JC : int atom index J ICC : float - constraint length + constraint length verbose : bool, optional """ if not hasattr(self, "CONSTRAINT"): @@ -722,7 +856,7 @@ def add_new_CONSTRAINT(self, IC:int, JC:int, ICC:float, verbose=False): self.CONSTRAINT.NCON = 0 if not hasattr(self, "BONDSTRETCHTYPE"): self.add_block(blocktitle="BONDSTRETCHTYPE", content=list(), verbose=verbose) - + # find the bondstretchtype number or create new bondstretchtype bond_type_number = 0 iterator = 1 @@ -733,47 +867,47 @@ def add_new_CONSTRAINT(self, IC:int, JC:int, ICC:float, verbose=False): else: iterator += 1 bond_type_number = iterator - if iterator > len(self.BONDSTRETCHTYPE.content):#bond type was not found -> add new bondtype + if iterator > len(self.BONDSTRETCHTYPE.content): # bond type was not found -> add new bondtype self.BONDSTRETCHTYPE.content.append(newBondStretchType) self.BONDSTRETCHTYPE.NBTY += 1 self.CONSTRAINT.content.append(blocks.constraint_type(IC=IC, JC=JC, ICC=bond_type_number)) self.CONSTRAINT.NCON += 1 - def add_new_TEMPERATUREGROUPS(self, number:str, verbose=False): + def add_new_TEMPERATUREGROUPS(self, number: str, verbose=False): if not hasattr(self, "TEMPERATUREGROUPS"): - defaultContent=['0', 'Dummy'] + defaultContent = ["0", "Dummy"] self.add_block(blocktitle="TEMPERATUREGROUPS", content=defaultContent, verbose=verbose) self.TEMPERATUREGROUPS.content.append([number]) - self.TEMPERATUREGROUPS.content.remove(['Dummy']) + self.TEMPERATUREGROUPS.content.remove(["Dummy"]) else: if len(self.TEMPERATUREGROUPS.content) < 1: self.TEMPERATUREGROUPS.content.append(["0"]) self.TEMPERATUREGROUPS.content.append([number]) - self.TEMPERATUREGROUPS.content[0][0] = str(int(self.TEMPERATUREGROUPS.content[0][0])+1) + self.TEMPERATUREGROUPS.content[0][0] = str(int(self.TEMPERATUREGROUPS.content[0][0]) + 1) - def add_new_SOLUTEMOLECULES(self, number:str, verbose=False): + def add_new_SOLUTEMOLECULES(self, number: str, verbose=False): if not hasattr(self, "SOLUTEMOLECULES"): - defaultContent=['0', 'Dummy'] + defaultContent = ["0", "Dummy"] self.add_block(blocktitle="SOLUTEMOLECULES", content=defaultContent, verbose=verbose) self.SOLUTEMOLECULES.content.append([number]) - self.SOLUTEMOLECULES.content.remove(['Dummy']) + self.SOLUTEMOLECULES.content.remove(["Dummy"]) else: if len(self.SOLUTEMOLECULES.content) < 1: self.SOLUTEMOLECULES.content.append(["0"]) self.SOLUTEMOLECULES.content.append([number]) - self.SOLUTEMOLECULES.content[0][0] = str(int(self.SOLUTEMOLECULES.content[0][0])+1) + self.SOLUTEMOLECULES.content[0][0] = str(int(self.SOLUTEMOLECULES.content[0][0]) + 1) - def add_new_PRESSUREGROUPS(self, number:str, verbose=False): + def add_new_PRESSUREGROUPS(self, number: str, verbose=False): if not hasattr(self, "PRESSUREGROUPS"): - defaultContent=['0', 'Dummy'] + defaultContent = ["0", "Dummy"] self.add_block(blocktitle="PRESSUREGROUPS", content=defaultContent, verbose=verbose) self.PRESSUREGROUPS.content.append([number]) - self.PRESSUREGROUPS.content.remove(['Dummy']) + self.PRESSUREGROUPS.content.remove(["Dummy"]) else: if len(self.PRESSUREGROUPS.content) < 1: self.PRESSUREGROUPS.content.append(["0"]) self.PRESSUREGROUPS.content.append([number]) - self.PRESSUREGROUPS.content[0][0] = str(int(self.PRESSUREGROUPS.content[0][0])+1) + self.PRESSUREGROUPS.content[0][0] = str(int(self.PRESSUREGROUPS.content[0][0]) + 1) def get_mass(self) -> float: """ @@ -790,7 +924,7 @@ def get_mass(self) -> float: mass += i.MASS return mass - def get_diff_to_top(self, top:TopType): + def get_diff_to_top(self, top: TopType): for block in self._block_order[1:]: if hasattr(self, block): if hasattr(top, block): @@ -799,7 +933,3 @@ def get_diff_to_top(self, top:TopType): print("self: " + str(getattr(self, block))) print("top: " + str(getattr(top, block))) print("\n") - - - - diff --git a/pygromos/files/trajectory/_general_trajectory.py b/pygromos/files/trajectory/_general_trajectory.py index 38c14741..5fa13ff1 100644 --- a/pygromos/files/trajectory/_general_trajectory.py +++ b/pygromos/files/trajectory/_general_trajectory.py @@ -19,7 +19,7 @@ """ -#imports +# imports import collections, os, re import pandas import numpy @@ -28,21 +28,22 @@ from pygromos.files.trajectory.blocks import trajectory_blocks as blocks from pygromos.utils import bash -class _General_Trajectory(): - #attribute annotation: - database:pandas.DataFrame - path:str - _future_file:bool #if code is executed async, this helps organizing. - _gromos_file_ending:str +class _General_Trajectory: - def __init__(self, input_value:(str or None), auto_save=True, stride:int=1, skip:int=0): + # attribute annotation: + database: pandas.DataFrame + path: str + _future_file: bool # if code is executed async, this helps organizing. + _gromos_file_ending: str + + def __init__(self, input_value: (str or None), auto_save=True, stride: int = 1, skip: int = 0): if input_value == None: self.TITLE = "Empty Trajectory" - self.database = pandas.DataFrame({'' : []}) + self.database = pandas.DataFrame({"": []}) elif isinstance(input_value, str): - if(input_value.endswith(".gz")): + if input_value.endswith(".gz"): tmp_input = bash.compress_gzip(input_value, extract=True) self._read_from_file(input_path=tmp_input, auto_save=auto_save, stride=stride, skip=skip) bash.compress_gzip(tmp_input) @@ -56,8 +57,8 @@ def __init__(self, input_value:(str or None), auto_save=True, stride:int=1, skip for tmp_traj_file in input_value[1:]: self += __class__(tmp_traj_file, auto_save=False) - if(auto_save): - auto_save_path = input_value[0]+".h5" + if auto_save: + auto_save_path = input_value[0] + ".h5" self.write(auto_save_path) elif isinstance(input_value.__class__, __class__) or issubclass(input_value.__class__, __class__): @@ -67,19 +68,18 @@ def __init__(self, input_value:(str or None), auto_save=True, stride:int=1, skip else: raise IOError("Constructor not found") - def __str__(self)->str: - if(isinstance(self.TITLE, str)): - msg="Trajectory: \n\t"+"\n\t".join(self.TITLE.split("\n"))+"\n" - elif(isinstance(self.TITLE, list)): - msg="Trajectory: \n\t"+"\n\t".join(self.TITLE)+"\n" + def __str__(self) -> str: + if isinstance(self.TITLE, str): + msg = "Trajectory: \n\t" + "\n\t".join(self.TITLE.split("\n")) + "\n" + elif isinstance(self.TITLE, list): + msg = "Trajectory: \n\t" + "\n\t".join(self.TITLE) + "\n" else: print(type(self.TITLE), self.TITLE) - msg="Trajectory: \n\t"+"\n\t".join(str(self.TITLE).split("\n"))+"\n" - + msg = "Trajectory: \n\t" + "\n\t".join(str(self.TITLE).split("\n")) + "\n" - msg+= "Type: \n\t" +str(self.__class__.__name__) + "\n" - msg+="Frames: \t"+str(self.database.shape[0])+"\t Columns:\t"+str(self.database.shape[1])+"\n" - msg+="\n" + msg += "Type: \n\t" + str(self.__class__.__name__) + "\n" + msg += "Frames: \t" + str(self.database.shape[0]) + "\t Columns:\t" + str(self.database.shape[1]) + "\n" + msg += "\n" return msg def __repr__(self): @@ -125,10 +125,16 @@ def add_traj(self, traj, skip_new_0=False, auto_detect_skip=True, correct_time=T trajA + trajB """ if type(traj) != type(self): - raise Exception("Different types of trajectories can not be added (concatenated).\nTry to add a " + str(type(self)) + " class of the same type") + raise Exception( + "Different types of trajectories can not be added (concatenated).\nTry to add a " + + str(type(self)) + + " class of the same type" + ) if traj.database.shape[1] != self.database.shape[1]: - raise Warning("trajectories database shapes do not match!\n Please check if this is expected\n" - "first shape: "+str(self.database.shape)+"\tsecond shape: "+str(traj.database.shape)+"\n") + raise Warning( + "trajectories database shapes do not match!\n Please check if this is expected\n" + "first shape: " + str(self.database.shape) + "\tsecond shape: " + str(traj.database.shape) + "\n" + ) # get end data from first trajectory step_offset = int(self.database.step.iloc[-1]) time_offset = float(self.database.time.iloc[-1]) @@ -136,19 +142,20 @@ def add_traj(self, traj, skip_new_0=False, auto_detect_skip=True, correct_time=T # copy and modify second trajectory new_data = traj.database.copy(deep=True) - + if skip_new_0: new_data = new_data.iloc[1:] elif auto_detect_skip: new_frame = new_data.iloc[0].iloc[2:] old_frame = self.database.iloc[-1].iloc[2:] - if (new_frame.equals(old_frame)) and new_frame.keys() == old_frame.keys(): #check if the firstStep==lastStep without considering the time + if ( + new_frame.equals(old_frame) + ) and new_frame.keys() == old_frame.keys(): # check if the firstStep==lastStep without considering the time if all([numpy.allclose(new_frame[x], old_frame[x]) for x in new_frame.keys()]): new_data = new_data.iloc[1:] elif correct_time: if delta_time_self == traj.get_time_step(): time_offset += delta_time_self - if correct_time: new_data.step += step_offset @@ -160,44 +167,44 @@ def add_traj(self, traj, skip_new_0=False, auto_detect_skip=True, correct_time=T del new_data return new_traj - def _read_from_file(self, input_path:str, auto_save:bool=True, stride:int=1, skip:int=0): - if(input_path.endswith(".h5")): + def _read_from_file(self, input_path: str, auto_save: bool = True, stride: int = 1, skip: int = 0): + if input_path.endswith(".h5"): self._read_db_from_hf5(input_path=input_path) - elif(re.search( "\.tr.$", input_path)): # + elif re.search("\.tr.$", input_path): # self._read_trajectory(input_path=input_path, auto_save=auto_save, stride=stride, skip=skip) else: raise IOError("Did not understand the file ending of given file path: ", input_path) - def _read_db_from_hf5(self, input_path:str, title: str="Read from hdf save \nContains only database\n"): + def _read_db_from_hf5(self, input_path: str, title: str = "Read from hdf save \nContains only database\n"): self.TITLE = title self.database = pandas.read_hdf(path_or_buf=input_path, key=input_path.split(".")[-1]) - def _raw_read_trajectory(self, input_path:str, stride:int=1, skip:int=0) -> collections.defaultdict: - #define temp storage + def _raw_read_trajectory(self, input_path: str, stride: int = 1, skip: int = 0) -> collections.defaultdict: + # define temp storage header = {} data = [] dataInTimestep = {} block = [] - blockname = '' - - #set contorl bool + blockname = "" + + # set contorl bool isInTimeStep = False isInBlock = False - timeStepCounter = 0-skip + timeStepCounter = 0 - skip # start to read the trajectory - with open(input_path, 'r') as infile: + with open(input_path, "r") as infile: for line in infile: if isInTimeStep: - if timeStepCounter >= 0 and timeStepCounter%stride==0: + if timeStepCounter >= 0 and timeStepCounter % stride == 0: if isInBlock: if not line.strip().startswith("END"): block.append(line) else: isInBlock = False - dataInTimestep.update({blockname:block}) + dataInTimestep.update({blockname: block}) else: - if line.strip().startswith('#') or line.strip() == '': + if line.strip().startswith("#") or line.strip() == "": continue blockname = line.strip() block = [] @@ -208,16 +215,16 @@ def _raw_read_trajectory(self, input_path:str, stride:int=1, skip:int=0) -> coll timeStepCounter += 1 else: if line.strip().startswith("TIMESTEP"): - timeStepCounter += 1 + timeStepCounter += 1 else: if isInBlock: if not line.strip().startswith("END"): block.append(line) else: isInBlock = False - header.update({blockname:block}) + header.update({blockname: block}) else: - if line.strip().startswith('#') or line.strip() == '': + if line.strip().startswith("#") or line.strip() == "": continue blockname = line.strip() block = [] @@ -225,21 +232,24 @@ def _raw_read_trajectory(self, input_path:str, stride:int=1, skip:int=0) -> coll if blockname.startswith("TIMESTEP"): isInTimeStep = True if isInTimeStep: - #final time step finish since no smarter way to detect end of Timestep + # final time step finish since no smarter way to detect end of Timestep data.append(dataInTimestep) else: raise ValueError("No timestep found") del dataInTimestep, block, blockname - return {"header":header, "body":data} + return {"header": header, "body": data} - def _read_trajectory(self, input_path:str, stride:int=1, skip:int=0, auto_save=True): + def _read_trajectory(self, input_path: str, stride: int = 1, skip: int = 0, auto_save=True): if auto_save: # check if parsed file exists and is up to date - if os.path.isfile(input_path+".h5"): - if pathlib.Path(input_path).stat().st_ctime < pathlib.Path(input_path+".h5").stat().st_ctime: - self._read_db_from_hf5(input_path=input_path+".h5", title="Reread from hdf save \nContains only database\nfor all other blocks please make a fresh import") - - if (not os.path.exists(input_path)): + if os.path.isfile(input_path + ".h5"): + if pathlib.Path(input_path).stat().st_ctime < pathlib.Path(input_path + ".h5").stat().st_ctime: + self._read_db_from_hf5( + input_path=input_path + ".h5", + title="Reread from hdf save \nContains only database\nfor all other blocks please make a fresh import", + ) + + if not os.path.exists(input_path): raise IOError("Could not find File: ", input_path) else: table = [] @@ -252,7 +262,7 @@ def _read_trajectory(self, input_path:str, stride:int=1, skip:int=0, auto_save=T table_entry = {} for blocktitle, block in time_step_entry.items(): if not hasattr(blocks, blocktitle): - raise IOError("No trajectory block found named: "+blocktitle) + raise IOError("No trajectory block found named: " + blocktitle) tmp_block = getattr(blocks, blocktitle)(block) table_entry.update(tmp_block.to_dict()) table.append(table_entry) @@ -260,14 +270,18 @@ def _read_trajectory(self, input_path:str, stride:int=1, skip:int=0, auto_save=T del table, table_entry, data, header, body self.database = db if auto_save: - self.write(input_path+".h5") + self.write(input_path + ".h5") - def write(self, output_path:str)->str: - if(not output_path.endswith(".h5")): + def write(self, output_path: str) -> str: + if not output_path.endswith(".h5"): output_path += ".h5" - if(not os.path.exists(os.path.dirname(output_path))): - raise IOError("Could not find target directory for outfile! target dir: " + str(os.path.dirname(output_path))) - self.database.to_hdf(path_or_buf=output_path, key=output_path.split(".")[-1]) #TODO: @Marc is the key arg here correct, or rather not using it? + if not os.path.exists(os.path.dirname(output_path)): + raise IOError( + "Could not find target directory for outfile! target dir: " + str(os.path.dirname(output_path)) + ) + self.database.to_hdf( + path_or_buf=output_path, key=output_path.split(".")[-1] + ) # TODO: @Marc is the key arg here correct, or rather not using it? self.path = output_path return output_path @@ -278,16 +292,3 @@ def get_time_step(self): return float(self.database.time.iloc[-1]) else: return float(self.database.time.iloc[-1]) - float(self.database.time.iloc[-2]) - - - - - - - - - - - - - diff --git a/pygromos/files/trajectory/blocks/energy_trajectory_subblock.py b/pygromos/files/trajectory/blocks/energy_trajectory_subblock.py index 8680ca61..7f944a6e 100644 --- a/pygromos/files/trajectory/blocks/energy_trajectory_subblock.py +++ b/pygromos/files/trajectory/blocks/energy_trajectory_subblock.py @@ -1,10 +1,11 @@ import numpy as np -class _general_pandas_energy_trajectory_subblock(): - def __init__(self, content ): + +class _general_pandas_energy_trajectory_subblock: + def __init__(self, content): self.content = [] for i in content: - if(i.startswith("#")): #cometimes there are inconsistent comment lines...( + if i.startswith("#"): # cometimes there are inconsistent comment lines...( continue try: self.content.append(i.split()) @@ -16,9 +17,10 @@ def __init__(self, content ): for j in i: self.list.append(j) - def to_dict(self)->dict: + def to_dict(self) -> dict: return {self.blockName: np.array(self.list, dtype=np.float64)} + class _general_pandas_energy_trajectory_subblock_numerated(_general_pandas_energy_trajectory_subblock): # first define some static variables for the stupid gromos format num_energy_baths = 0 @@ -55,27 +57,29 @@ def __init__(self, content, subsubblock_number_code="energy"): except: print("no good value found for the number of subsubblocks") if num_subsubblocks <= 0: - raise KeyError("invalid iterator with value: "+str(num_subsubblocks)) - + raise KeyError("invalid iterator with value: " + str(num_subsubblocks)) + # set value to static varibale for all futer values if subsubblock_number_code == "energy": _general_pandas_energy_trajectory_subblock_numerated.num_energy_baths = num_subsubblocks elif subsubblock_number_code == "force": _general_pandas_energy_trajectory_subblock_numerated.num_force_groups = num_subsubblocks - _general_pandas_energy_trajectory_subblock_numerated.num_nbforce_groups = sum([x for x in range(1, num_subsubblocks+1)]) + _general_pandas_energy_trajectory_subblock_numerated.num_nbforce_groups = sum( + [x for x in range(1, num_subsubblocks + 1)] + ) elif subsubblock_number_code == "states": _general_pandas_energy_trajectory_subblock_numerated.num_num_states = num_subsubblocks elif subsubblock_number_code == "lambda": _general_pandas_energy_trajectory_subblock_numerated.num_lambdas = num_subsubblocks elif subsubblock_number_code == "temp": _general_pandas_energy_trajectory_subblock_numerated.num_temp_groups = num_subsubblocks - - #print("subblock number set to: " + str(num_subsubblocks) + " for: " + subsubblock_number_code) + + # print("subblock number set to: " + str(num_subsubblocks) + " for: " + subsubblock_number_code) self.extra_line_for_num += 1 # loop over all energy baths, import the data and format to numpy matrix for itr_line in range(num_subsubblocks): new_line = self.content[itr_line + self.extra_line_for_num] - self.matrixList.append(new_line) + self.matrixList.append(new_line) self.matrix = np.array(self.matrixList, dtype=np.float64) @@ -83,7 +87,6 @@ def to_dict(self) -> dict: return {self.blockName: self.matrix} - class totals(_general_pandas_energy_trajectory_subblock): def __init__(self, content): super().__init__(content) @@ -92,97 +95,111 @@ def __init__(self, content): def to_dict(self) -> dict: return super().to_dict() + class baths(_general_pandas_energy_trajectory_subblock_numerated): def __init__(self, content): super().__init__(content, subsubblock_number_code="energy") self.blockName = "baths" - + def to_dict(self) -> dict: return super().to_dict() + class bonded(_general_pandas_energy_trajectory_subblock_numerated): def __init__(self, content): super().__init__(content, subsubblock_number_code="force") self.blockName = "bonded" - + def to_dict(self) -> dict: return super().to_dict() + class nonbonded(_general_pandas_energy_trajectory_subblock_numerated): def __init__(self, content): super().__init__(content, subsubblock_number_code="nbforce") self.blockName = "nonbonded" - + def to_dict(self) -> dict: return super().to_dict() + class special(_general_pandas_energy_trajectory_subblock_numerated): def __init__(self, content): super().__init__(content, subsubblock_number_code="force") self.blockName = "special" - + def to_dict(self) -> dict: return super().to_dict() + class eds(_general_pandas_energy_trajectory_subblock): def __init__(self, content): super().__init__(content) self.blockName = "eds" - + def to_dict(self) -> dict: return super().to_dict() + class precalclam(_general_pandas_energy_trajectory_subblock): def __init__(self, content): super().__init__(content) self.blockName = "precalclam" - + def to_dict(self) -> dict: return super().to_dict() + class mass(_general_pandas_energy_trajectory_subblock): - def __init__(self, content ): - super().__init__(content ) + def __init__(self, content): + super().__init__(content) self.blockName = "mass" - + def to_dict(self) -> dict: return super().to_dict() + class temperature(_general_pandas_energy_trajectory_subblock_numerated): def __init__(self, content): super().__init__(content, subsubblock_number_code="temp") self.blockName = "temperature" - + def to_dict(self) -> dict: return super().to_dict() + class volume(_general_pandas_energy_trajectory_subblock): def __init__(self, content): super().__init__(content) self.blockName = "volume" - + def to_dict(self) -> dict: return super().to_dict() + class pressure(_general_pandas_energy_trajectory_subblock): def __init__(self, content): super().__init__(content) self.blockName = "pressure" - + def to_dict(self) -> dict: return super().to_dict() + class xxx_copy_xxx(_general_pandas_energy_trajectory_subblock): def __init__(self, content): super().__init__(content) self.blockName = "xxx" - + def to_dict(self) -> dict: return super().to_dict() + """ TRG specials: """ + + class lam(_general_pandas_energy_trajectory_subblock): def __init__(self, content): super().__init__(content) diff --git a/pygromos/files/trajectory/blocks/trajectory_blocks.py b/pygromos/files/trajectory/blocks/trajectory_blocks.py index 50087ea0..1be39778 100644 --- a/pygromos/files/trajectory/blocks/trajectory_blocks.py +++ b/pygromos/files/trajectory/blocks/trajectory_blocks.py @@ -1,15 +1,17 @@ import numpy as np from pygromos.files.trajectory.blocks import energy_trajectory_subblock as ene_sub_block -class _general_pandas_trajectory_block(): + +class _general_pandas_trajectory_block: def __init__(self, content): self.content = content def __eq__(self, __o: object) -> bool: return (self.content == __o.content) and (self.__class__ == __o.__class__) - def to_dict(self)->dict: - return {"default_block": self.content} #Only use for Debuging + def to_dict(self) -> dict: + return {"default_block": self.content} # Only use for Debuging + class _general_pandas_tre_block(_general_pandas_trajectory_block): def __init__(self, content): @@ -30,33 +32,36 @@ def to_dict(self) -> dict: if line.strip() == "": continue if line.startswith("# "): - subblock_name = line.strip().replace("# ","") - subblock_content.update({subblock_name:[]}) + subblock_name = line.strip().replace("# ", "") + subblock_content.update({subblock_name: []}) else: subblock_content[subblock_name].append(line.strip()) - + for subblocktitle, subblock in subblock_content.items(): - if("lambda" == subblocktitle): #Exceptions for TRG - tmp_sub_block = getattr(ene_sub_block, "lam")(subblock) #stupid block naming.... but they couldn't have known - elif("ABdih" == subblocktitle): + if "lambda" == subblocktitle: # Exceptions for TRG + tmp_sub_block = getattr(ene_sub_block, "lam")( + subblock + ) # stupid block naming.... but they couldn't have known + elif "ABdih" == subblocktitle: subblocktitle = "precalclam" tmp_sub2.extend(subblock) tmp_sub_block = getattr(ene_sub_block, subblocktitle)(tmp_sub2) - elif("numstates" == subblocktitle): + elif "numstates" == subblocktitle: subblocktitle = "eds" tmp_sub_block = getattr(ene_sub_block, subblocktitle)(subblock) - elif("precalclam"== subblocktitle or "eds" == subblocktitle): + elif "precalclam" == subblocktitle or "eds" == subblocktitle: continue - elif("nr_lambdas" == subblocktitle): + elif "nr_lambdas" == subblocktitle: tmp_sub2 = subblock continue else: tmp_sub_block = getattr(ene_sub_block, subblocktitle)(subblock) return_dict.update(tmp_sub_block.to_dict()) - + return return_dict + class TIMESTEP(_general_pandas_trajectory_block): def __init__(self, content): super().__init__(content) @@ -65,50 +70,55 @@ def __init__(self, content): self.time = float(entries[1]) def to_dict(self) -> dict: - return {"step":self.step, "time":self.time} + return {"step": self.step, "time": self.time} + """ TRC Blocks: """ + + class POSITIONRED(_general_pandas_trajectory_block): def __init__(self, content): super().__init__(content) - + def to_dict(self) -> dict: return_dict = {} iterator = 1 for line in self.content: - if line.strip().startswith('#') or line.strip() == '': + if line.strip().startswith("#") or line.strip() == "": continue - return_dict.update({"POS_"+str(iterator):np.array(line.strip().split()).astype(np.float)}) + return_dict.update({"POS_" + str(iterator): np.array(line.strip().split()).astype(np.float)}) iterator += 1 return return_dict -class SHAKEFAILPOSITION(_general_pandas_trajectory_block): + +class SHAKEFAILPOSITION(_general_pandas_trajectory_block): def __init__(self, content): super().__init__(content) - + def to_dict(self) -> dict: return_dict = {} iterator = 1 for line in self.content: - if line.strip().startswith('#') or line.strip() == '': + if line.strip().startswith("#") or line.strip() == "": continue - return_dict.update({"SHK_"+str(iterator):np.array(line.strip().split()).astype(np.float)}) + return_dict.update({"SHK_" + str(iterator): np.array(line.strip().split()).astype(np.float)}) iterator += 1 return return_dict -class SHAKEFAILPREVPOSITION(_general_pandas_trajectory_block): + +class SHAKEFAILPREVPOSITION(_general_pandas_trajectory_block): def __init__(self, content): super().__init__(content) - + def to_dict(self) -> dict: return_dict = {} iterator = 1 for line in self.content: - if line.strip().startswith('#') or line.strip() == '': + if line.strip().startswith("#") or line.strip() == "": continue - return_dict.update({"SHKP_"+str(iterator):np.array(line.strip().split()).astype(np.float)}) + return_dict.update({"SHKP_" + str(iterator): np.array(line.strip().split()).astype(np.float)}) iterator += 1 return return_dict @@ -116,17 +126,18 @@ def to_dict(self) -> dict: class REFPOSITION(_general_pandas_trajectory_block): def __init__(self, content): super().__init__(content) - + def to_dict(self) -> dict: return_dict = {} iterator = 1 for line in self.content: - if line.strip().startswith('#') or line.strip() == '': + if line.strip().startswith("#") or line.strip() == "": continue - return_dict.update({"LAT_"+str(iterator):np.array(line.strip().split()).astype(np.float)}) + return_dict.update({"LAT_" + str(iterator): np.array(line.strip().split()).astype(np.float)}) iterator += 1 return return_dict + class GENBOX(_general_pandas_trajectory_block): def __init__(self, content): super().__init__(content) @@ -135,16 +146,19 @@ def to_dict(self) -> dict: if len(self.content) < 4: raise IOError("GENBOX block incomplete in trajectory") return_dict = {} - return_dict.update({"genbox":self.content[0]}) - return_dict.update({"length":np.array(self.content[1].strip().split()).astype(np.float)}) - return_dict.update({"angles":np.array(self.content[2].strip().split()).astype(np.float)}) - return_dict.update({"watEver":np.array(self.content[3].strip().split()).astype(np.float)}) + return_dict.update({"genbox": self.content[0]}) + return_dict.update({"length": np.array(self.content[1].strip().split()).astype(np.float)}) + return_dict.update({"angles": np.array(self.content[2].strip().split()).astype(np.float)}) + return_dict.update({"watEver": np.array(self.content[3].strip().split()).astype(np.float)}) return return_dict + """ TRE Blocks: """ + + class ENERGY03(_general_pandas_tre_block): def __init__(self, content): super().__init__(content) @@ -160,13 +174,15 @@ def __init__(self, content): def to_dict(self) -> dict: return super().to_dict() + """ TRG Blocks: """ + + class FREEENERDERIVS03(_general_pandas_tre_block): def __init__(self, content): super().__init__(content) def to_dict(self) -> dict: return super().to_dict() - diff --git a/pygromos/files/trajectory/tre.py b/pygromos/files/trajectory/tre.py index 525aa8e4..c711dc98 100644 --- a/pygromos/files/trajectory/tre.py +++ b/pygromos/files/trajectory/tre.py @@ -15,30 +15,60 @@ """ -#imports +# imports import pandas as pd import numpy as np from typing import Tuple, Dict import pygromos.files.trajectory._general_trajectory as traj -from pygromos.files.trajectory.tre_field_libs.ene_fields import gromos_2020_tre_block_names_table,gromos_tre_block_names_table +from pygromos.files.trajectory.tre_field_libs.ene_fields import ( + gromos_2020_tre_block_names_table, + gromos_tre_block_names_table, +) from pygromos.analysis import energy_analysis as ea + class Tre(traj._General_Trajectory): """ - The Tre files are results from Gromos simulations, that store all the calculated energies and properties during the simulation. + The Tre files are results from Gromos simulations, that store all the calculated energies and properties during the simulation. """ - _gromos_file_ending:str = "tre" - _contributions_nonbonded_names: Tuple[str] = ("Lennard-Jones", "Coulomb/RF", "lattice sum real", "lattice sum reciproc") + + _gromos_file_ending: str = "tre" + _contributions_nonbonded_names: Tuple[str] = ( + "Lennard-Jones", + "Coulomb/RF", + "lattice sum real", + "lattice sum reciproc", + ) _contributions_bonded_names: Tuple[str] = ("bond", "angle", "improper", "dihedral", "crossdihedral") _contributions_baths: Tuple[str] = ("kinetic total", "centre of mass", "internal/rotational") - _contributions_special: Tuple[str] = ("constraints", "pos. restraints", "dist. restraints", "disfield res", "dihe. restr.", "SASA", "SASA volume","jvalue","rdc","local elevation", "path integral", "angle restraint") - _contributions_temperature: Tuple[str] = ('total', 'com', 'ir', 'scaling factor') - - def __init__(self, input_value: (str, None), auto_save=True, stride:int=1, skip:int=0, _ene_ana_names:gromos_tre_block_names_table = gromos_2020_tre_block_names_table): - """ - Build a Gromos energy trajectory file (.tre) + _contributions_special: Tuple[str] = ( + "constraints", + "pos. restraints", + "dist. restraints", + "disfield res", + "dihe. restr.", + "SASA", + "SASA volume", + "jvalue", + "rdc", + "local elevation", + "path integral", + "angle restraint", + ) + _contributions_temperature: Tuple[str] = ("total", "com", "ir", "scaling factor") + + def __init__( + self, + input_value: (str, None), + auto_save=True, + stride: int = 1, + skip: int = 0, + _ene_ana_names: gromos_tre_block_names_table = gromos_2020_tre_block_names_table, + ): + """ + Build a Gromos energy trajectory file (.tre) Parameters ---------- @@ -55,121 +85,122 @@ def __init__(self, input_value: (str, None), auto_save=True, stride:int=1, skip: """ super().__init__(input_value, auto_save=auto_save, stride=stride, skip=skip) self.tre_block_name_table = _ene_ana_names - - if("time" in self.database.columns): + + if "time" in self.database.columns: self.time = self.database.time - if("step" in self.database.columns): + if "step" in self.database.columns: self.step = self.database.step - """-------------------------------------------------------------- Basic getters for Subblocks and Subsubblocks ----------------------------------------------------------------- - + The following functions, return well formated values from the tre trajectories. - - + + ENERGY03 - fields: """ def get_totals(self) -> pd.DataFrame: """ - get all totals of the system + get all totals of the system """ - #print(self.database["totals"][0].shape, self.database["totals"][0]) - if(not hasattr(self, "totals")): - self.totals = pd.DataFrame(data =np.stack(self.database["totals"].to_numpy()), index=self.database.time, columns=self.tre_block_name_table.totals_subblock_names) + # print(self.database["totals"][0].shape, self.database["totals"][0]) + if not hasattr(self, "totals"): + self.totals = pd.DataFrame( + data=np.stack(self.database["totals"].to_numpy()), + index=self.database.time, + columns=self.tre_block_name_table.totals_subblock_names, + ) else: pass return self.totals def get_totene(self) -> pd.DataFrame: """ - get the total System energy / per time + get the total System energy / per time """ - self.totene = self.get_totals()['totene'] + self.totene = self.get_totals()["totene"] return self.totene def get_totkin(self) -> pd.DataFrame: """ - get the total kinetic Energy / per time + get the total kinetic Energy / per time """ - self.totkin = self.get_totals()['totkin'] + self.totkin = self.get_totals()["totkin"] return self.totkin def get_totpot(self) -> pd.DataFrame: """ - get the total potential Energy / per time + get the total potential Energy / per time """ - self.totpot = self.get_totals()['totpot'] + self.totpot = self.get_totals()["totpot"] return self.totpot def get_totcov(self) -> pd.DataFrame: """ - get the total covalent contribution/ per time + get the total covalent contribution/ per time """ - self.totcov = self.get_totals()['totcov'] + self.totcov = self.get_totals()["totcov"] return self.totcov def get_totbonded(self) -> pd.DataFrame: """ - get the total bonded contribution/ per time + get the total bonded contribution/ per time """ - self.totbonded = self.get_totals()['totbond'] + self.totbonded = self.get_totals()["totbond"] return self.totbonded def get_totangle(self) -> pd.DataFrame: """ - get the total angle contribution/ per time + get the total angle contribution/ per time """ - self.totangle = self.get_totals()['totangle'] + self.totangle = self.get_totals()["totangle"] return self.totangle def get_totdihedral(self) -> pd.DataFrame: """ - get the total dihedral contribution/ per time + get the total dihedral contribution/ per time """ - self.totdihedral = self.get_totals()['totdihedral'] + self.totdihedral = self.get_totals()["totdihedral"] return self.totdihedral def get_totnonbonded(self) -> pd.DataFrame: """ - get the total nonbonded contribution/ per time + get the total nonbonded contribution/ per time """ - self.totnonbonded = self.get_totals()['totnonbonded'] + self.totnonbonded = self.get_totals()["totnonbonded"] return self.totnonbonded def get_totlj(self) -> pd.DataFrame: """ - get the total lennard jones contribution/ per time + get the total lennard jones contribution/ per time """ - self.totlj = self.get_totals()['totlj'] + self.totlj = self.get_totals()["totlj"] return self.totlj - def get_totcrf(self) -> pd.DataFrame: + def get_totcrf(self) -> pd.DataFrame: """ - get the total columbic reactionfield contribution/ per time + get the total columbic reactionfield contribution/ per time """ - self.totcrf = self.get_totals()['totcrf'] + self.totcrf = self.get_totals()["totcrf"] return self.totcrf - def get_baths(self)->pd.DataFrame: - """ - extract data of the baths block + def get_baths(self) -> pd.DataFrame: + """ + extract data of the baths block """ - return self._set_data(attibute_name='baths', - rows_name="baths", - field_names=self._contributions_baths) + return self._set_data(attibute_name="baths", rows_name="baths", field_names=self._contributions_baths) - def get_bondedContributions(self)->Dict[int,pd.DataFrame]: - """ - extract data of the bonded block + def get_bondedContributions(self) -> Dict[int, pd.DataFrame]: """ - return self._set_data(attibute_name='bondedContributions', - rows_name="bonded", - field_names=self._contributions_bonded_names) + extract data of the bonded block + """ + return self._set_data( + attibute_name="bondedContributions", rows_name="bonded", field_names=self._contributions_bonded_names + ) - def get_nonbondedContributions(self)->Dict[int, Dict[int, pd.DataFrame]]: + def get_nonbondedContributions(self) -> Dict[int, Dict[int, pd.DataFrame]]: """ This function returns a nice formatted dictionary for the nonbonded Contributions according to the Force groups of the tre file. @@ -184,35 +215,43 @@ def get_nonbondedContributions(self)->Dict[int, Dict[int, pd.DataFrame]]: ValueError returns Value error, if the dimensionality of the different contributions does not fit to the _nonbonded_contribution_names. """ - if(not hasattr(self, "forceGroupNonbondedContributions")): - #Check contibution_dimensionalities + if not hasattr(self, "forceGroupNonbondedContributions"): + # Check contibution_dimensionalities nFFContributions = self.database.nonbonded[0].shape[1] - if(nFFContributions!=len(self._contributions_nonbonded_names)): - raise ValueError("The dimensionality of the NonbondedContributions is not corresponding to the expected dimensionality.\n expected: "+str(len(_contributions_nonbonded_names))+" \t found: "+str(nFFContributions)) - - #Get the number of force groups: + if nFFContributions != len(self._contributions_nonbonded_names): + raise ValueError( + "The dimensionality of the NonbondedContributions is not corresponding to the expected dimensionality.\n expected: " + + str(len(_contributions_nonbonded_names)) + + " \t found: " + + str(nFFContributions) + ) + + # Get the number of force groups: nForceGroup = self._get_numberOfForceGroupsFromNonbondeds() - - #Generate dictionary for the different contributions + + # Generate dictionary for the different contributions t = 0 forceGroupNonbondedContributions = {} - for i in range(1, 1+nForceGroup): - forceGroupNonbondedContributions[i]={} - for j in range(1, 1+nForceGroup): - forceGroupNonbondedContributions[i][j]=pd.DataFrame(list(self.database.nonbonded.apply(lambda x: x[i+j-2])), columns=self._contributions_nonbonded_names) - t+=1 + for i in range(1, 1 + nForceGroup): + forceGroupNonbondedContributions[i] = {} + for j in range(1, 1 + nForceGroup): + forceGroupNonbondedContributions[i][j] = pd.DataFrame( + list(self.database.nonbonded.apply(lambda x: x[i + j - 2])), + columns=self._contributions_nonbonded_names, + ) + t += 1 self.forceGroupNonbondedContributions = forceGroupNonbondedContributions return self.forceGroupNonbondedContributions - def get_specialContributions(self)->Dict[int,pd.DataFrame]: #CHECK THIS - """ - extract data of the special block + def get_specialContributions(self) -> Dict[int, pd.DataFrame]: # CHECK THIS + """ + extract data of the special block """ - return self._set_data(attibute_name='specialContributions', - rows_name="special", - field_names=self._contributions_special) + return self._set_data( + attibute_name="specialContributions", rows_name="special", field_names=self._contributions_special + ) - def get_eds(self)->pd.DataFrame: + def get_eds(self) -> pd.DataFrame: """ Get EDS energies if present. @@ -221,21 +260,31 @@ def get_eds(self)->pd.DataFrame: pd.DataFrame returns datafrae with columns for each endstate. """ - if(not hasattr(self, "eds")): + if not hasattr(self, "eds"): num_states = self.database["eds"][0][0] - if(num_states>0): - state_strings =[[column+"_"+str(state_row) for column in self.tre_block_name_table.eds_subblock_names_singleState] for state_row in range(1, 1+int(num_states))] + if num_states > 0: + state_strings = [ + [ + column + "_" + str(state_row) + for column in self.tre_block_name_table.eds_subblock_names_singleState + ] + for state_row in range(1, 1 + int(num_states)) + ] self.tre_block_name_table.eds_subblock_names = ["numstates"] self.tre_block_name_table.eds_subblock_names.extend(list(np.concatenate(state_strings))) else: self.tre_block_name_table.eds_subblock_names = ["numstates"] - self.eds = pd.DataFrame(data=np.stack(self.database["eds"].to_numpy()), index=self.database.time, columns=self.tre_block_name_table.eds_subblock_names) + self.eds = pd.DataFrame( + data=np.stack(self.database["eds"].to_numpy()), + index=self.database.time, + columns=self.tre_block_name_table.eds_subblock_names, + ) else: pass - + return self.eds - def get_precalclam(self)->pd.DataFrame: + def get_precalclam(self) -> pd.DataFrame: """ Get the energies calculated for the different defined lambda values in a trajectory. @@ -244,26 +293,34 @@ def get_precalclam(self)->pd.DataFrame: pd.DataFrame return the energies calculated for the different lambda values. """ - if(not hasattr(self, "precalclam")): + if not hasattr(self, "precalclam"): num_lam = self.database["precalclam"][0][0] - if(num_lam>0): - state_strings =[[column+"_"+str(state_row) for column in self.tre_block_name_table.lam_subblock_names_singleLam] for state_row in range(1, 1+int(num_lam))] + if num_lam > 0: + state_strings = [ + [column + "_" + str(state_row) for column in self.tre_block_name_table.lam_subblock_names_singleLam] + for state_row in range(1, 1 + int(num_lam)) + ] self.tre_block_name_table.lam_subblock_names = ["nr_lambdas"] self.tre_block_name_table.lam_subblock_names.extend(list(np.concatenate(state_strings))) self.tre_block_name_table.lam_subblock_names.extend(["A_dihedral", "B_dihedral"]) else: self.tre_block_name_table.lam_subblock_names = ["nr_lambdas", "A_dihedral", "B_dihedral"] - self.precalclam = pd.DataFrame(data=np.stack(self.database["precalclam"].to_numpy()), index=self.database.time, columns=self.tre_block_name_table.lam_subblock_names) + self.precalclam = pd.DataFrame( + data=np.stack(self.database["precalclam"].to_numpy()), + index=self.database.time, + columns=self.tre_block_name_table.lam_subblock_names, + ) else: pass - + return self.precalclam """ VOLUMEPRESSURE03 - fields: """ - def get_mass(self)->pd.Series: + + def get_mass(self) -> pd.Series: """ returns the systems mass per timestep @@ -273,8 +330,8 @@ def get_mass(self)->pd.Series: series of mass per time """ return pd.Series(map(float, self.database.mass), name="mass", index=self.database.time) - - def get_temperature_Info(self)->Dict[int,pd.DataFrame]: + + def get_temperature_Info(self) -> Dict[int, pd.DataFrame]: """ temperature baths @@ -283,11 +340,13 @@ def get_temperature_Info(self)->Dict[int,pd.DataFrame]: Dict[int,pd.DataFrame] returns the full info of the temperature baths per bath """ - return self._set_data(attibute_name='temperatureInfo', - rows_name="temperature", - field_names=self._contributions_temperature) - - def get_temperature(self) -> pd.DataFrame: #CHECK THIS - tempcontrib:total com ir scaling factor + return self._set_data( + attibute_name="temperatureInfo", rows_name="temperature", field_names=self._contributions_temperature + ) + + def get_temperature( + self, + ) -> pd.DataFrame: # CHECK THIS - tempcontrib:total com ir scaling factor """ Get the temperature in Kelvin for all temperature baths for every time step @@ -304,13 +363,14 @@ def get_temperature(self) -> pd.DataFrame: #CHECK THIS - tempcontrib:total return pd.DataFrame(tmps, index=self.database.time) - """ + """ UTILS """ - def _set_data(self, attibute_name:str, rows_name:str, field_names:Tuple[str])->pd.DataFrame: + + def _set_data(self, attibute_name: str, rows_name: str, field_names: Tuple[str]) -> pd.DataFrame: """_summary_ This function extracts generially the information of a column per time - + Parameters ---------- attibute_name : str @@ -319,27 +379,32 @@ def _set_data(self, attibute_name:str, rows_name:str, field_names:Tuple[str])->p name of the block, that shall be extracted field_names : Tuple[str] name of the fields in each row - + Returns ------- pd.DataFrame contains the extracted information """ - if(not hasattr(self, attibute_name)): + if not hasattr(self, attibute_name): nDimGroups = self.database[rows_name][0].shape[0] - + setattr(self, attibute_name, {}) for i in range(nDimGroups): - getattr(self, attibute_name).update({i: pd.DataFrame(list(map(lambda x: list(x[i]), list(self.database[rows_name]))), - columns=field_names, - index=self.database.time)}) + getattr(self, attibute_name).update( + { + i: pd.DataFrame( + list(map(lambda x: list(x[i]), list(self.database[rows_name]))), + columns=field_names, + index=self.database.time, + ) + } + ) return getattr(self, attibute_name) - - def _get_numberOfForceGroupsFromNonbondeds(self)->int: + def _get_numberOfForceGroupsFromNonbondeds(self) -> int: """ This function gets the number of Force groups in the simulation from the nonbonded block. - + Returns ------- int @@ -347,15 +412,14 @@ def _get_numberOfForceGroupsFromNonbondeds(self)->int: """ nForceGroupDim = self.database.nonbonded[0].shape[0] - r=0 - for nForceGroup in range(1,nForceGroupDim+1): - r+=nForceGroup - if(r == nForceGroupDim): + r = 0 + for nForceGroup in range(1, nForceGroupDim + 1): + r += nForceGroup + if r == nForceGroupDim: return nForceGroup - elif(r>nForceGroupDim): + elif r > nForceGroupDim: raise Exception("That should not happen!") - - + """-------------------------------------------------------------- Additional predefined function for common analysis ----------------------------------------------------------------- @@ -371,8 +435,13 @@ def get_density(self) -> pd.DataFrame: pd.DataFrame Dataframe with the densities for all time steps """ - return pd.Series(list(self.database[["mass","volume"]].apply(lambda x: ea.get_density(mass=x[0][0], volume=x[1][0]), axis=1)), - index=self.database.time, name="density") + return pd.Series( + list( + self.database[["mass", "volume"]].apply(lambda x: ea.get_density(mass=x[0][0], volume=x[1][0]), axis=1) + ), + index=self.database.time, + name="density", + ) def get_Hvap(self, gas_traj, nMolecules=1, temperature=None) -> float: gas_totpot_energy = 0 @@ -384,10 +453,15 @@ def get_Hvap(self, gas_traj, nMolecules=1, temperature=None) -> float: raise TypeError("Did not understand the type of gas. Allowed are float (E_gas) or Tre (gas_trajectory)") liq_totpot_energy = self.get_totals_totpot().mean() - #get temperature from liq trajectory if not given + # get temperature from liq trajectory if not given if temperature is None: temperature = float(self.get_temperature().mean()[0]) # calculate heat of vaporization - self.heat_vap = ea.get_Hvap(liq_totpot_energy=liq_totpot_energy, gas_totpot_energy=gas_totpot_energy, temperature=temperature, nMolecules=nMolecules) + self.heat_vap = ea.get_Hvap( + liq_totpot_energy=liq_totpot_energy, + gas_totpot_energy=gas_totpot_energy, + temperature=temperature, + nMolecules=nMolecules, + ) return self.heat_vap diff --git a/pygromos/files/trajectory/tre_field_libs/ene_fields.py b/pygromos/files/trajectory/tre_field_libs/ene_fields.py index c940da8a..be2c7496 100644 --- a/pygromos/files/trajectory/tre_field_libs/ene_fields.py +++ b/pygromos/files/trajectory/tre_field_libs/ene_fields.py @@ -1,48 +1,220 @@ from typing import List -class gromos_tre_block_names_table(): - totals_subblock_names:List[str] - eds_subblock_names_singleState:List[str] - lam_subblock_names_singleLam:List[str] - + + +class gromos_tre_block_names_table: + totals_subblock_names: List[str] + eds_subblock_names_singleState: List[str] + lam_subblock_names_singleLam: List[str] + + class gromos_2015_tre_block_names_table(gromos_tre_block_names_table): - totals_subblock_names = ["totene","totkin","totpot","totcov","totbond","totangle","totimproper","totdihedral","totcrossdihedral","totnonbonded", - "totlj","totcrf","totls","totlspair","totlsreal","totlsk","totlsa","totlsself","totlssurf","totpolself","totspecial", - "totsasa","totsasavol","totconstraint","totdisres","totdisfieldres","totdihres","totposres","totjval","totxray","totle", - "totorder","totsymm", - "eds_vr,entropy","totqm","totbsleus","totrdc", "wip1"] + totals_subblock_names = [ + "totene", + "totkin", + "totpot", + "totcov", + "totbond", + "totangle", + "totimproper", + "totdihedral", + "totcrossdihedral", + "totnonbonded", + "totlj", + "totcrf", + "totls", + "totlspair", + "totlsreal", + "totlsk", + "totlsa", + "totlsself", + "totlssurf", + "totpolself", + "totspecial", + "totsasa", + "totsasavol", + "totconstraint", + "totdisres", + "totdisfieldres", + "totdihres", + "totposres", + "totjval", + "totxray", + "totle", + "totorder", + "totsymm", + "eds_vr,entropy", + "totqm", + "totbsleus", + "totrdc", + "wip1", + ] eds_subblock_names_singleState = ["total", "nonbonded", "special"] - eds_subblock_names = None #is generated on the fly in get_eds of TRE - depends on num_states -> simulation specific + eds_subblock_names = ( + None # is generated on the fly in get_eds of TRE - depends on num_states -> simulation specific + ) - lam_subblock_names_singleLam = ["A_e_lj", "B_e_lj", "A_e_crf", "B_e_crf", "AB_kinetic", "AB_bond", "AB_angle", "AB_improper", "AB_disres", "AB_dihres", "AB_disfld"] - lam_subblock_names = None #is generated on the fly in get_eds of TRE - depends on num_states -> simulation specific + lam_subblock_names_singleLam = [ + "A_e_lj", + "B_e_lj", + "A_e_crf", + "B_e_crf", + "AB_kinetic", + "AB_bond", + "AB_angle", + "AB_improper", + "AB_disres", + "AB_dihres", + "AB_disfld", + ] + lam_subblock_names = ( + None # is generated on the fly in get_eds of TRE - depends on num_states -> simulation specific + ) class gromos_2020_tre_block_names_table(gromos_tre_block_names_table): - totals_subblock_names = ["totene","totkin","totpot","totcov","totbond","totangle","totimproper","totdihedral","totcrossdihedral","totnonbonded", - "totlj","totcrf","totls","totlspair","totlsreal","totlsk","totlsa","totlsself","totlssurf","totpolself","totspecial", - "totsasa","totsasavol","totconstraint","totdisres","totdisfieldres","totdihres","totposres","totjval","totxray","totle", - "totorder","totsymm", - "eds_vr,entropy","totqm","totbsleus","totrdc","wip1","wip2","wip3","wip4","wip5","wip6", "wip7"] + totals_subblock_names = [ + "totene", + "totkin", + "totpot", + "totcov", + "totbond", + "totangle", + "totimproper", + "totdihedral", + "totcrossdihedral", + "totnonbonded", + "totlj", + "totcrf", + "totls", + "totlspair", + "totlsreal", + "totlsk", + "totlsa", + "totlsself", + "totlssurf", + "totpolself", + "totspecial", + "totsasa", + "totsasavol", + "totconstraint", + "totdisres", + "totdisfieldres", + "totdihres", + "totposres", + "totjval", + "totxray", + "totle", + "totorder", + "totsymm", + "eds_vr,entropy", + "totqm", + "totbsleus", + "totrdc", + "wip1", + "wip2", + "wip3", + "wip4", + "wip5", + "wip6", + "wip7", + ] eds_subblock_names_singleState = ["total", "nonbonded", "special", "offset"] - eds_subblock_names = None #is generated on the fly in get_eds of TRE - depends on num_states -> simulation specific + eds_subblock_names = ( + None # is generated on the fly in get_eds of TRE - depends on num_states -> simulation specific + ) - lam_subblock_names_singleLam = ["A_e_lj", "B_e_lj", "A_e_crf", "B_e_crf", "AB_kinetic", "AB_bond", "AB_angle", "AB_improper", "AB_disres", "AB_dihres", "AB_disfld"] - lam_subblock_names = None #is generated on the fly in get_eds of TRE - depends on num_states -> simulation specific + lam_subblock_names_singleLam = [ + "A_e_lj", + "B_e_lj", + "A_e_crf", + "B_e_crf", + "AB_kinetic", + "AB_bond", + "AB_angle", + "AB_improper", + "AB_disres", + "AB_dihres", + "AB_disfld", + ] + lam_subblock_names = ( + None # is generated on the fly in get_eds of TRE - depends on num_states -> simulation specific + ) class gromos_2021_tre_block_names_table(gromos_tre_block_names_table): - totals_subblock_names = ["totene","totkin","totpot","totcov","totbond","totangle","totimproper","totdihedral","totcrossdihedral","totnonbonded", - "totlj","totcrf","totls","totlspair","totlsreal","totlsk","totlsa","totlsself","totlssurf","totpolself","totspecial", - "totsasa","totsasavol","totconstraint","totdisres","totdisfieldres","totdihres","totposres","totjval","totxray","totle", - "totorder","totsymm", - "eds_vmix", "eds_vr", "eds_emax", "eds_emin", "eds_globmin", "eds_globminfluc", - "entropy", - "totqm","totbsleus", "totrdc", "totangres", "wip1","wip2","wip3","wip4","wip5","wip6"] + totals_subblock_names = [ + "totene", + "totkin", + "totpot", + "totcov", + "totbond", + "totangle", + "totimproper", + "totdihedral", + "totcrossdihedral", + "totnonbonded", + "totlj", + "totcrf", + "totls", + "totlspair", + "totlsreal", + "totlsk", + "totlsa", + "totlsself", + "totlssurf", + "totpolself", + "totspecial", + "totsasa", + "totsasavol", + "totconstraint", + "totdisres", + "totdisfieldres", + "totdihres", + "totposres", + "totjval", + "totxray", + "totle", + "totorder", + "totsymm", + "eds_vmix", + "eds_vr", + "eds_emax", + "eds_emin", + "eds_globmin", + "eds_globminfluc", + "entropy", + "totqm", + "totbsleus", + "totrdc", + "totangres", + "wip1", + "wip2", + "wip3", + "wip4", + "wip5", + "wip6", + ] eds_subblock_names_singleState = ["total", "nonbonded", "special", "offset"] - eds_subblock_names = None #is generated on the fly in get_eds of TRE - depends on num_states -> simulation specific + eds_subblock_names = ( + None # is generated on the fly in get_eds of TRE - depends on num_states -> simulation specific + ) - lam_subblock_names_singleLam = ["A_e_lj", "B_e_lj", "A_e_crf", "B_e_crf", "AB_kinetic", "AB_bond", "AB_angle", "AB_improper", "AB_disres", "AB_dihres", "AB_disfld"] - lam_subblock_names = None #is generated on the fly in get_eds of TRE - depends on num_states -> simulation specific \ No newline at end of file + lam_subblock_names_singleLam = [ + "A_e_lj", + "B_e_lj", + "A_e_crf", + "B_e_crf", + "AB_kinetic", + "AB_bond", + "AB_angle", + "AB_improper", + "AB_disres", + "AB_dihres", + "AB_disfld", + ] + lam_subblock_names = ( + None # is generated on the fly in get_eds of TRE - depends on num_states -> simulation specific + ) diff --git a/pygromos/files/trajectory/trg.py b/pygromos/files/trajectory/trg.py index fd687830..ca3170f2 100644 --- a/pygromos/files/trajectory/trg.py +++ b/pygromos/files/trajectory/trg.py @@ -15,37 +15,60 @@ """ -#imports +# imports import pandas as pd import numpy as np import pygromos.files.trajectory._general_trajectory as traj -class gromos_2020_trg_block_names_table(): - totals_subblock_names = ["dHdl", "dKdl", "dVdl",] + ["WIP" for x in range(40)] - precalclam_subblock = ["nr_lambdas", "A_e_lj", "B_e_lj", "A_e_crf", "B_e_crf", "AB_kinetic", "AB_bond", "AB_angle", "AB_improper", "AB_disres", "AB_dihres", "AB_disfld",] + +class gromos_2020_trg_block_names_table: + totals_subblock_names = [ + "dHdl", + "dKdl", + "dVdl", + ] + ["WIP" for x in range(40)] + precalclam_subblock = [ + "nr_lambdas", + "A_e_lj", + "B_e_lj", + "A_e_crf", + "B_e_crf", + "AB_kinetic", + "AB_bond", + "AB_angle", + "AB_improper", + "AB_disres", + "AB_dihres", + "AB_disfld", + ] + class Trg(traj._General_Trajectory): - _gromos_file_ending:str = "trg" + _gromos_file_ending: str = "trg" - def __init__(self, input_value: str or None, auto_save=True, stride:int=1, skip:int=0): + def __init__(self, input_value: str or None, auto_save=True, stride: int = 1, skip: int = 0): super().__init__(input_value, auto_save=auto_save, stride=stride, skip=skip) self.block_name_table = gromos_2020_trg_block_names_table def get_totals(self) -> pd.DataFrame: - self.totals = pd.DataFrame(data = np.stack(self.database["totals"].to_numpy()), columns=self.block_name_table.totals_subblock_names) + self.totals = pd.DataFrame( + data=np.stack(self.database["totals"].to_numpy()), columns=self.block_name_table.totals_subblock_names + ) return self.totals def get_lambdas(self) -> pd.DataFrame: - self.totals = pd.DataFrame(data = np.stack(self.database["lambda"].to_numpy()), columns=["lambda"]) + self.totals = pd.DataFrame(data=np.stack(self.database["lambda"].to_numpy()), columns=["lambda"]) return self.totals def get_precalclam(self) -> pd.DataFrame: groups = self.database["precalclam"].iloc[0][0] adapted_cols = [self.block_name_table.precalclam_subblock[0]] - for i in range(1,int(groups)+1): - adapted_cols.extend(list(map(lambda x: str(x)+"_"+str(i), self.block_name_table.precalclam_subblock[1:]))) + for i in range(1, int(groups) + 1): + adapted_cols.extend( + list(map(lambda x: str(x) + "_" + str(i), self.block_name_table.precalclam_subblock[1:])) + ) adapted_cols.extend(["A_dihedral", "B_dihedral"]) - self.totals = pd.DataFrame(data = np.stack(self.database["precalclam"].to_numpy()), columns=adapted_cols) + self.totals = pd.DataFrame(data=np.stack(self.database["precalclam"].to_numpy()), columns=adapted_cols) return self.totals diff --git a/pygromos/gromos/gromosBashSyntaxParser.py b/pygromos/gromos/gromosBashSyntaxParser.py index 3a29ab74..986333a5 100644 --- a/pygromos/gromos/gromosBashSyntaxParser.py +++ b/pygromos/gromos/gromosBashSyntaxParser.py @@ -1,8 +1,3 @@ - - - - - class gromosBashSyntaxParser: """ Helper class to parse general gromos bash syntax @@ -11,7 +6,7 @@ class gromosBashSyntaxParser: """ @staticmethod - def multiplyArgumentParser(args:(str or list(str)), multiplier:(int or list(int)) = 1) -> str: + def multiplyArgumentParser(args: (str or list(str)), multiplier: (int or list(int)) = 1) -> str: """ Parser for multiplier syntax to gromos scripts @@ -24,18 +19,18 @@ def multiplyArgumentParser(args:(str or list(str)), multiplier:(int or list(int) multiplier : int or list(int) the multiplier for each argument provided in args """ - command = "" + command = "" if multiplier != 1: - if type(args) == list and len(args) >= 1: - if (len(args) != len(multiplier)): + if type(args) == list and len(args) >= 1: + if len(args) != len(multiplier): raise ValueError("multiplier does not match the number of arguments provided!") else: for mult, topo in zip(multiplier, args): - command+= str(mult) + ":" + topo+" " + command += str(mult) + ":" + topo + " " else: command = str(multiplier) + ":" + args else: - if type(args) == list and len(args) >= 1: + if type(args) == list and len(args) >= 1: command = " ".join(args) else: command = args @@ -47,4 +42,4 @@ def atomSliceParser(): @staticmethod def moleculeSliceParser(): - raise NotImplementedError("WIP") \ No newline at end of file + raise NotImplementedError("WIP") diff --git a/pygromos/gromos/gromosPP.py b/pygromos/gromos/gromosPP.py index 1b851185..26a96036 100644 --- a/pygromos/gromos/gromosPP.py +++ b/pygromos/gromos/gromosPP.py @@ -19,7 +19,6 @@ from pygromos.gromos.utils import gromosTypeConverter - class _gromosPPbase: """ GromosPP @@ -34,9 +33,9 @@ class _gromosPPbase: """ _bin: str = "" - _isValid:bool = False + _isValid: bool = False - def __init__(self, gromosPP_bin_dir:str=None): + def __init__(self, gromosPP_bin_dir: str = None): """ Constructing a gromosPP object. @@ -45,17 +44,21 @@ def __init__(self, gromosPP_bin_dir:str=None): bin : str, optional This is the path to the folder containing the binaries of gromosXX. If None, the bash enviroment variables will be used. """ - #lazy me - doc text for functions: - functions_text = "\n Methods:\n ---------\n" + "\n".join(["\t\t" + x for x in dir(self) if (not x.startswith("_") and callable(getattr(self, x)))]) - self.__doc__ = self.__doc__+functions_text + # lazy me - doc text for functions: + functions_text = "\n Methods:\n ---------\n" + "\n".join( + ["\t\t" + x for x in dir(self) if (not x.startswith("_") and callable(getattr(self, x)))] + ) + self.__doc__ = self.__doc__ + functions_text - if(isinstance(gromosPP_bin_dir, str) and not "None" == gromosPP_bin_dir): + if isinstance(gromosPP_bin_dir, str) and not "None" == gromosPP_bin_dir: self._bin = gromosPP_bin_dir + "/" else: self._bin = "" try: - self.make_top(out_top_path=os.devnull, in_building_block_lib_path=mtb, in_parameter_lib_path=ifp, in_sequence="CH4") + self.make_top( + out_top_path=os.devnull, in_building_block_lib_path=mtb, in_parameter_lib_path=ifp, in_sequence="CH4" + ) self._isValid = True except: self._isValid = False @@ -67,14 +70,22 @@ def __repr__(self): return self.__str__() @property - def bin(self)->Union[str, None]: - if(not hasattr(self, "_bin") or self._bin == "" ): + def bin(self) -> Union[str, None]: + if not hasattr(self, "_bin") or self._bin == "": return None else: return self._bin @gromosTypeConverter - def pdb2gromos(self, in_pdb_path:str, in_top_path:str, out_cnf_path:str=None, in_lib_path:str=pdb_lib, _binary_name:str= "pdb2g96", verbose:bool = False)->str: + def pdb2gromos( + self, + in_pdb_path: str, + in_top_path: str, + out_cnf_path: str = None, + in_lib_path: str = pdb_lib, + _binary_name: str = "pdb2g96", + verbose: bool = False, + ) -> str: """ This is a wrapper for pdb2gromos. It executes the gromosPP binary. @@ -98,25 +109,36 @@ def pdb2gromos(self, in_pdb_path:str, in_top_path:str, out_cnf_path:str=None, in -------- For more information checkout the Gromos Manual """ - if(out_cnf_path==None): + if out_cnf_path == None: out_cnf_path = str(os.path.splitext(os.path.basename(in_pdb_path))[0]) + ".cnf" - if(not out_cnf_path.endswith(".cnf")): + if not out_cnf_path.endswith(".cnf"): out_cnf_path += ".cnf" - command = self._bin + _binary_name + " @pdb " + in_pdb_path + " @topo " + in_top_path + " @out " + out_cnf_path - if(in_lib_path!=None): + if in_lib_path != None: command += " @lib " + in_lib_path - command +="\n" + command += "\n" - if (verbose): print(command) + if verbose: + print(command) p = bash.execute(command, catch_STD=True) - if (verbose): print(p.stdout.readlines()) + if verbose: + print(p.stdout.readlines()) return out_cnf_path @gromosTypeConverter - def pdb2seq(self, in_pdb_path:str, out_path:str= "", pH:float=7.4, select:str = "ALL", gff:str = "54a7", add_head:str= "NH3+", add_tail:str= "COO-", _binary:str= "pdb2seq")->str: + def pdb2seq( + self, + in_pdb_path: str, + out_path: str = "", + pH: float = 7.4, + select: str = "ALL", + gff: str = "54a7", + add_head: str = "NH3+", + add_tail: str = "COO-", + _binary: str = "pdb2seq", + ) -> str: """ This function is translating a pdb into a sequence file, that can be used to generate for example topologies. @@ -151,19 +173,41 @@ def pdb2seq(self, in_pdb_path:str, out_path:str= "", pH:float=7.4, select:str = -------- For more information checkout the Gromos Manual """ - if(out_path== ""): - out_path = os.path.dirname(in_pdb_path) + "/" + str(os.path.splitext(os.path.basename(in_pdb_path))[0]) + ".seq" - command = self._bin + _binary + " @develop @pdb " + in_pdb_path + " @pH " + str(pH) + " @select " + select + " @gff " + gff - if(add_head != ""): - command += " @head "+add_head - if(add_tail != ""): - command += " @tail "+add_tail + if out_path == "": + out_path = ( + os.path.dirname(in_pdb_path) + "/" + str(os.path.splitext(os.path.basename(in_pdb_path))[0]) + ".seq" + ) + command = ( + self._bin + + _binary + + " @develop @pdb " + + in_pdb_path + + " @pH " + + str(pH) + + " @select " + + select + + " @gff " + + gff + ) + if add_head != "": + command += " @head " + add_head + if add_tail != "": + command += " @tail " + add_tail command += " > " + out_path + " \n" bash.execute(command) return out_path @gromosTypeConverter - def make_top(self, out_top_path:str, in_building_block_lib_path: str, in_parameter_lib_path: str, in_sequence:str, in_solvent:str= "H2O", additional_options="\n", _binary_name:str= "make_top")->str: + def make_top( + self, + out_top_path: str, + in_building_block_lib_path: str, + in_parameter_lib_path: str, + in_sequence: str, + in_solvent: str = "H2O", + additional_options="\n", + _binary_name: str = "make_top", + ) -> str: """ This wrapper uses make_top to generate a topology file. @@ -186,27 +230,35 @@ def make_top(self, out_top_path:str, in_building_block_lib_path: str, in_paramet For more information checkout the Gromos Manual """ - if(os.path.exists(in_sequence)): - seq_file = open(in_sequence, "r") - in_sequence = "".join(seq_file.readlines()) - - args = ["@build " + in_building_block_lib_path, - "@param " + in_parameter_lib_path, - "@seq " + in_sequence, - "@solv " + in_solvent] - #arg_path = os.path.dirname(out_top_path) + "/topargs.arg" - #arg_file = open(arg_path, "w") - #arg_file.write("\n".join(args)) - #arg_file.close() - #"@f " + arg_path - command = self._bin +_binary_name +" "+" ".join(args) + if os.path.exists(in_sequence): + seq_file = open(in_sequence, "r") + in_sequence = "".join(seq_file.readlines()) + + args = [ + "@build " + in_building_block_lib_path, + "@param " + in_parameter_lib_path, + "@seq " + in_sequence, + "@solv " + in_solvent, + ] + # arg_path = os.path.dirname(out_top_path) + "/topargs.arg" + # arg_file = open(arg_path, "w") + # arg_file.write("\n".join(args)) + # arg_file.close() + # "@f " + arg_path + command = self._bin + _binary_name + " " + " ".join(args) bash.execute(command, catch_STD=out_top_path) return out_top_path @gromosTypeConverter - def com_top(self, in_topo_paths:(str or List[str]), topo_multiplier:(int or List[int])=1, out_top_path:str= "combined_out.top", - take_topology_params_of_file:int=1, take_solvent_parameters_of_file:int=1, - _binary_name:str="com_top")->str: #Todo: also take lists as input ! bschroed + def com_top( + self, + in_topo_paths: (str or List[str]), + topo_multiplier: (int or List[int]) = 1, + out_top_path: str = "combined_out.top", + take_topology_params_of_file: int = 1, + take_solvent_parameters_of_file: int = 1, + _binary_name: str = "com_top", + ) -> str: # Todo: also take lists as input ! bschroed """ Combine multiple topologies Parameters @@ -227,23 +279,39 @@ def com_top(self, in_topo_paths:(str or List[str]), topo_multiplier:(int or List make_top For more information checkout the Gromos Manual """ - if(len(in_topo_paths)==1 and type(in_topo_paths[0])==list): + if len(in_topo_paths) == 1 and type(in_topo_paths[0]) == list: in_topo_paths = in_topo_paths[0] - if(not out_top_path.endswith(".top")): - out_top_path+= ".top" + if not out_top_path.endswith(".top"): + out_top_path += ".top" - if(isinstance(in_topo_paths, list) and isinstance(topo_multiplier, int)): + if isinstance(in_topo_paths, list) and isinstance(topo_multiplier, int): topo_multiplier = [topo_multiplier for x in range(len(in_topo_paths))] topo_argument = gromosBashSyntaxParser.multiplyArgumentParser(in_topo_paths, topo_multiplier) - command = self._bin + _binary_name + " @topo " + topo_argument + " @param " + str(take_topology_params_of_file) + " @solv " + str(take_solvent_parameters_of_file) + command = ( + self._bin + + _binary_name + + " @topo " + + topo_argument + + " @param " + + str(take_topology_params_of_file) + + " @solv " + + str(take_solvent_parameters_of_file) + ) bash.execute(command, catch_STD=out_top_path) return out_top_path @gromosTypeConverter - def dfmult(self, in_endstate_file_paths: List[str], in_reference_state_file_path:str, out_file_path:str= "dfmult_temp.out", - temperature:float=298, _binary_name:str= "dfmult", verbose:bool=False)->str: + def dfmult( + self, + in_endstate_file_paths: List[str], + in_reference_state_file_path: str, + out_file_path: str = "dfmult_temp.out", + temperature: float = 298, + _binary_name: str = "dfmult", + verbose: bool = False, + ) -> str: """ This funciton wraps dfmult of the gromos suite, it is used to calculate the free energy of a EDS simulation. .. math:: \frac{\langle e^{V_{i}-V_{R} \rangle_{R}}{\langle e^{V_{i}-V_{R} \rangle_{R}} @@ -269,24 +337,52 @@ def dfmult(self, in_endstate_file_paths: List[str], in_reference_state_file_path For more information checkout the Gromos Manual """ - #formulate command - if(verbose): print(" ".join(in_endstate_file_paths)) - command = self._bin + _binary_name + " @stateR " + in_reference_state_file_path + " @temp " + str(temperature) + " @endstates " + " ".join(in_endstate_file_paths) + " > " + out_file_path + "\n" - if(verbose): print(command) - #do - ret = bash.execute_os(command, verbose=verbose) - if(verbose): print(ret.readlines()) + # formulate command + if verbose: + print(" ".join(in_endstate_file_paths)) + command = ( + self._bin + + _binary_name + + " @stateR " + + in_reference_state_file_path + + " @temp " + + str(temperature) + + " @endstates " + + " ".join(in_endstate_file_paths) + + " > " + + out_file_path + + "\n" + ) + if verbose: + print(command) + # do + ret = bash.execute_os(command, verbose=verbose) + if verbose: + print(ret.readlines()) bash.wait_for_fileSystem(out_file_path) return out_file_path @gromosTypeConverter - def frameout(self, in_top_path:str, in_coord_path:str, periodic_boundary_condition:str, - out_file_path:str=None, out_file_format:str=None, single_file:bool=None, - gather:(int or str)=None, include:str= "SOLUTE", - reference_structure_path:str=None, atomsfit:str=None, - frames:int=None, time:int=None, dt:int=None, notimeblock:bool=None, - _binary_name:str= "frameout", verbose:bool=False)->str: + def frameout( + self, + in_top_path: str, + in_coord_path: str, + periodic_boundary_condition: str, + out_file_path: str = None, + out_file_format: str = None, + single_file: bool = None, + gather: (int or str) = None, + include: str = "SOLUTE", + reference_structure_path: str = None, + atomsfit: str = None, + frames: int = None, + time: int = None, + dt: int = None, + notimeblock: bool = None, + _binary_name: str = "frameout", + verbose: bool = False, + ) -> str: """ this wrapper wraps frameout. frameout is a tool, that can be used for example to convert gromos coordinate files or to recenter them or .... @@ -334,67 +430,90 @@ def frameout(self, in_top_path:str, in_coord_path:str, periodic_boundary_conditi """ options = "" - if(out_file_format != None): + if out_file_format != None: options += "@outformat " + str(out_file_format) + " " periodic_boundary_condition = "@pbc " + periodic_boundary_condition + " " - if (gather != None): + if gather != None: periodic_boundary_condition += " " + str(gather) + " " - if(include!=None): - options+="@include "+str(include)+" " - if(single_file!=None): + if include != None: + options += "@include " + str(include) + " " + if single_file != None: options += "@single " - if(atomsfit!=None and reference_structure_path!=None): + if atomsfit != None and reference_structure_path != None: options += "@ref " + str(reference_structure_path) + " @atomsfit " + atomsfit + " " - if(not isinstance(time, type(None))): - options += "@time "+str(time)+" " - if(not isinstance(time, type(None)) and not isinstance(dt, type(None))): - options += " "+str(dt)+" " - if(notimeblock): - options += "@time "+str(0) - - if(frames !=None ): + if not isinstance(time, type(None)): + options += "@time " + str(time) + " " + if not isinstance(time, type(None)) and not isinstance(dt, type(None)): + options += " " + str(dt) + " " + if notimeblock: + options += "@time " + str(0) + + if frames != None: raise NotImplementedError("Chosen Options for frameout not implemented yet!") - if(out_file_path!=None): - orig =os.getcwd()+"/FRAME_00001."+out_file_format + if out_file_path != None: + orig = os.getcwd() + "/FRAME_00001." + out_file_format else: - orig =os.getcwd()+"/FRAME* " - if(not isinstance(out_file_format, type(None))): - out_file_path = os.path.dirname(in_coord_path) + "/FRAME_00001."+out_file_format + orig = os.getcwd() + "/FRAME* " + if not isinstance(out_file_format, type(None)): + out_file_path = os.path.dirname(in_coord_path) + "/FRAME_00001." + out_file_format else: - out_file_path = os.path.dirname(in_coord_path) + "/FRAME_00001."+in_coord_path.split(".")[-1] - - command = self._bin + _binary_name + " @topo " + str(in_top_path) + " @traj " + str(in_coord_path) + " " + periodic_boundary_condition + " " + options - if verbose: print("gromosPP.frameout: command:\n" +command) - - #DO + out_file_path = os.path.dirname(in_coord_path) + "/FRAME_00001." + in_coord_path.split(".")[-1] + + command = ( + self._bin + + _binary_name + + " @topo " + + str(in_top_path) + + " @traj " + + str(in_coord_path) + + " " + + periodic_boundary_condition + + " " + + options + ) + if verbose: + print("gromosPP.frameout: command:\n" + command) + + # DO try: ret = bash.execute(command, catch_STD=True) - if(verbose): print("STDOUT: ", "\n".join(ret.stdout.readlines())) + if verbose: + print("STDOUT: ", "\n".join(ret.stdout.readlines())) except Exception as err: - print("gromosPP.frameout: could not exectue framout:\n"+str(err.args)) - raise Exception("gromosPP.frameout: could not exectue framout:\n"+str(err.args)) - + print("gromosPP.frameout: could not exectue framout:\n" + str(err.args)) + raise Exception("gromosPP.frameout: could not exectue framout:\n" + str(err.args)) bash.wait_for_fileSystem(check_paths=orig, regex_mode=True) - - #move to output + # move to output try: bash.move_file(orig, out_file_path) except Exception as err: - print("gromosPP.frameout: could not move new FRAME*.pdb file to out-parameter:\n"+str(err.args)) + print("gromosPP.frameout: could not move new FRAME*.pdb file to out-parameter:\n" + str(err.args)) raise Exception("gromosPP.frameout: could not move new FRAME*.pdb file to out-parameter:\n" + str(err.args)) return out_file_path @gromosTypeConverter - def ene_ana(self, in_ene_ana_library_path: str, in_en_file_paths: str, in_properties: str, - out_energy_folder_path: str, out_files_prefix: str = None, out_files_suffix: str = None, - in_topo: str = None, time: float = None, single_file: bool = False,return_outstat_also:bool=False, - verbose: bool = False, _binary_name: str = "ene_ana", workdir: bool = False) -> (List[str] or str): + def ene_ana( + self, + in_ene_ana_library_path: str, + in_en_file_paths: str, + in_properties: str, + out_energy_folder_path: str, + out_files_prefix: str = None, + out_files_suffix: str = None, + in_topo: str = None, + time: float = None, + single_file: bool = False, + return_outstat_also: bool = False, + verbose: bool = False, + _binary_name: str = "ene_ana", + workdir: bool = False, + ) -> (List[str] or str): """ This is a wrapper for ene_ana. @@ -426,33 +545,35 @@ def ene_ana(self, in_ene_ana_library_path: str, in_en_file_paths: str, in_proper """ # check input - if (type(in_properties) == list): + if type(in_properties) == list: in_properties = " ".join(in_properties) - elif (type(in_properties) == str): + elif type(in_properties) == str: pass else: raise IOError( - "gromosPP.ene_ana: got an format for potentials, that is unknown! (Please give a list of strings or a final string)\n" + str( - in_properties)) + "gromosPP.ene_ana: got an format for potentials, that is unknown! (Please give a list of strings or a final string)\n" + + str(in_properties) + ) - if (isinstance(in_en_file_paths, list)): + if isinstance(in_en_file_paths, list): in_en_file_paths = " ".join(in_en_file_paths) - elif (isinstance(in_en_file_paths, str)): + elif isinstance(in_en_file_paths, str): pass else: raise IOError( - "gromosPP.ene_ana: got an format for potentials, that is unknown! (Please give a list of strings or a final string)\n" + str( - in_en_file_paths)) + "gromosPP.ene_ana: got an format for potentials, that is unknown! (Please give a list of strings or a final string)\n" + + str(in_en_file_paths) + ) # manage nice prefix - if (out_files_prefix): + if out_files_prefix: prefix = out_files_prefix else: prefix = "" # manage nice suffix - if (out_files_suffix): - if (not out_files_suffix.startswith("_") and not out_files_prefix.endswith("_")): + if out_files_suffix: + if not out_files_suffix.startswith("_") and not out_files_prefix.endswith("_"): suffix = "_" + out_files_suffix else: suffix = out_files_suffix @@ -461,29 +582,44 @@ def ene_ana(self, in_ene_ana_library_path: str, in_en_file_paths: str, in_proper additional_options = "" - if (in_topo): + if in_topo: additional_options += " @topo " + str(in_topo) - if (not isinstance(time, type(None))): + if not isinstance(time, type(None)): additional_options += " @time " + str(time) original_pos = os.getcwd() - if (not workdir): + if not workdir: os.chdir(out_energy_folder_path) - if (in_en_file_paths.strip().endswith("trg") or in_en_file_paths.strip().endswith("trg.gz")): + if in_en_file_paths.strip().endswith("trg") or in_en_file_paths.strip().endswith("trg.gz"): in_file_form = "@fr_files" else: in_file_form = "@en_files" ##ene_ana command and log deletion if ene_ana was successfull.: - command = self._bin + _binary_name + " @library " + str(in_ene_ana_library_path) + " " + in_file_form + " " + str( - in_en_file_paths) + " @prop " + in_properties + " " + additional_options - - if (verbose): print("Isolate_energies") + command = ( + self._bin + + _binary_name + + " @library " + + str(in_ene_ana_library_path) + + " " + + in_file_form + + " " + + str(in_en_file_paths) + + " @prop " + + in_properties + + " " + + additional_options + ) + + if verbose: + print("Isolate_energies") try: - out_fun = bash.execute(command, verbose=verbose) + out_fun = bash.execute(command, verbose=verbose) except Exception as err: - raise Exception("gromosPP.ene_ana: could not read out energies:\n" + "\n".join(err.args) + "\n command used: " + command) + raise Exception( + "gromosPP.ene_ana: could not read out energies:\n" + "\n".join(err.args) + "\n command used: " + command + ) # Wait for file system. tmp_files = [] @@ -492,30 +628,36 @@ def ene_ana(self, in_ene_ana_library_path: str, in_en_file_paths: str, in_proper bash.wait_for_fileSystem(check_path, verbose=verbose) tmp_files.append(check_path) - if (not single_file): + if not single_file: try: # move results to outfolder and give them proper name result_files = [] - if (type(in_properties) == str): + if type(in_properties) == str: in_properties = in_properties.split() for prop in in_properties: orig_file = str(os.getcwd() + "/" + prop + ".dat") target_file = str(out_energy_folder_path + "/" + prefix + prop + suffix + ".dat") - if (target_file == orig_file): + if target_file == orig_file: pass else: bash.move_file(in_file_path=orig_file, out_file_path=target_file) result_files.append(target_file) except Exception as err: - raise Exception("gromosPP.ene_ana: could not move and rename Files:\n" + "\n".join(err.args) + "\n before use: " + command) + raise Exception( + "gromosPP.ene_ana: could not move and rename Files:\n" + + "\n".join(err.args) + + "\n before use: " + + command + ) bash.wait_for_fileSystem(result_files) else: - if (verbose): print("reading in tmp_files files:\t" + "\n\t".join(tmp_files)) + if verbose: + print("reading in tmp_files files:\t" + "\n\t".join(tmp_files)) # energy_properties = [pd.read_csv(in_ene_traj_path, header=0, delim_whitespace=True) for in_ene_traj_path in tmp_files] # fix columns @@ -526,10 +668,12 @@ def ene_ana(self, in_ene_ana_library_path: str, in_en_file_paths: str, in_proper new_cols = [x if ("time" in x) else x for x in new_cols] energy_property.columns = new_cols energy_property.pop("") - if (verbose): print(energy_property.columns) - if (verbose): print(energy_property.shape) + if verbose: + print(energy_property.columns) + if verbose: + print(energy_property.shape) - if (first): + if first: first = False concat_energy_traj = energy_property else: @@ -543,23 +687,31 @@ def ene_ana(self, in_ene_ana_library_path: str, in_en_file_paths: str, in_proper # remove old trajs for x in tmp_files: - if (os.path.exists(x)): + if os.path.exists(x): bash.remove_file(x) result_files = tmp_pandas_out - if (not workdir): + if not workdir: os.chdir(original_pos) bash.wait_for_fileSystem(result_files) - if(return_outstat_also): + if return_outstat_also: return result_files, out_fun else: return result_files @gromosTypeConverter - def gch(self, in_cnf_path:str, in_top_path:str, out_cnf_path:str, - tolerance:float=0.1, periodic_boundary_condition:str="v", gathering:str="cog", _binary_name="gch") -> str: + def gch( + self, + in_cnf_path: str, + in_top_path: str, + out_cnf_path: str, + tolerance: float = 0.1, + periodic_boundary_condition: str = "v", + gathering: str = "cog", + _binary_name="gch", + ) -> str: """ This function adds reasonable hydrogenpositions a coordinate file. @@ -578,15 +730,33 @@ def gch(self, in_cnf_path:str, in_top_path:str, out_cnf_path:str, out_cnf_path """ - command = self._bin + _binary_name + " @topo " + in_top_path + " @pos " + in_cnf_path + " @tol " + str(tolerance) + " " \ - "@pbc " + periodic_boundary_condition +" " + gathering + command = ( + self._bin + + _binary_name + + " @topo " + + in_top_path + + " @pos " + + in_cnf_path + + " @tol " + + str(tolerance) + + " " + "@pbc " + periodic_boundary_condition + " " + gathering + ) bash.execute(command, catch_STD=out_cnf_path) - + return out_cnf_path - def add_hydrogens(self, in_cnf_path:str, in_top_path:str, out_cnf_path:str, - tolerance:float=0.1, periodic_boundary_condition:str="v", gathering:str="cog", _binary_name="gch") -> str: + def add_hydrogens( + self, + in_cnf_path: str, + in_top_path: str, + out_cnf_path: str, + tolerance: float = 0.1, + periodic_boundary_condition: str = "v", + gathering: str = "cog", + _binary_name="gch", + ) -> str: """ This function protonates a coordinate file. @@ -605,21 +775,39 @@ def add_hydrogens(self, in_cnf_path:str, in_top_path:str, out_cnf_path:str, out_cnf_path """ - self.gch( in_cnf_path=in_cnf_path, in_top_path=in_top_path, out_cnf_path=out_cnf_path, - tolerance=tolerance, periodic_boundary_condition=periodic_boundary_condition, gathering=gathering, _binary_name=_binary_name) - + self.gch( + in_cnf_path=in_cnf_path, + in_top_path=in_top_path, + out_cnf_path=out_cnf_path, + tolerance=tolerance, + periodic_boundary_condition=periodic_boundary_condition, + gathering=gathering, + _binary_name=_binary_name, + ) @gromosTypeConverter - def sim_box(self, in_top_path:str, in_cnf_path:str, in_solvent_cnf_file_path:str, out_cnf_path:str= "", - periodic_boundary_condition: str = "r", gathering_method:str=None, minwall:float=0.8, threshold:float=None, rotate:str=None, - boxsize:bool=False, _binary_name="sim_box", verbose=False)->str: + def sim_box( + self, + in_top_path: str, + in_cnf_path: str, + in_solvent_cnf_file_path: str, + out_cnf_path: str = "", + periodic_boundary_condition: str = "r", + gathering_method: str = None, + minwall: float = 0.8, + threshold: float = None, + rotate: str = None, + boxsize: bool = False, + _binary_name="sim_box", + verbose=False, + ) -> str: """ - When simulating a molecule in solution or in a crystal containing solvent + When simulating a molecule in solution or in a crystal containing solvent molecules, the atomic coordinates of the solvent molecules are to be - generated, if they are not available from experiment. Program sim_box can + generated, if they are not available from experiment. Program sim_box can solvate a solute in a pre-equilibrated box of solvent molecules. The file specifying the solvent configuration should contain a BOX block with the - dimensions corresponding to the pre-equilibrated density. The solvent + dimensions corresponding to the pre-equilibrated density. The solvent topology is read from the solvent block in the specified topology. Parameters @@ -654,49 +842,101 @@ def sim_box(self, in_top_path:str, in_cnf_path:str, in_solvent_cnf_file_path:str str return the path to the resulting cnf path. """ - - - + command_suffix = "" - if(out_cnf_path== ""): - out_cnf_path = os.path.dirname(in_cnf_path) + "/" + str(os.path.splitext(os.path.basename(in_cnf_path))[0]) + "_solvent.cnf" - if(rotate!=None): - command_suffix+= " @rotate " - if(gathering_method!=None): - command_suffix+= " @gather " + str(gathering_method) - if(boxsize): - command_suffix+= " @boxsize " - if(threshold!=None): - command_suffix+= " @thresh "+str(threshold) - if(minwall!=None): - command_suffix+= " @minwall " + str(minwall) - - command= self._bin + _binary_name + " @topo " + in_top_path + " @pbc " + periodic_boundary_condition + " @pos " + in_cnf_path + " @solvent " + in_solvent_cnf_file_path + " " + command_suffix + if out_cnf_path == "": + out_cnf_path = ( + os.path.dirname(in_cnf_path) + + "/" + + str(os.path.splitext(os.path.basename(in_cnf_path))[0]) + + "_solvent.cnf" + ) + if rotate != None: + command_suffix += " @rotate " + if gathering_method != None: + command_suffix += " @gather " + str(gathering_method) + if boxsize: + command_suffix += " @boxsize " + if threshold != None: + command_suffix += " @thresh " + str(threshold) + if minwall != None: + command_suffix += " @minwall " + str(minwall) + + command = ( + self._bin + + _binary_name + + " @topo " + + in_top_path + + " @pbc " + + periodic_boundary_condition + + " @pos " + + in_cnf_path + + " @solvent " + + in_solvent_cnf_file_path + + " " + + command_suffix + ) p = bash.execute(command, verbose=verbose, catch_STD=out_cnf_path) return out_cnf_path @gromosTypeConverter - def ran_box(self, in_top_path:str, in_cnf_path:str, out_cnf_path:str= "", - periodic_boundary_condition: str = "r", nmolecule:int = 1, dens:float = 1.0, threshold:float=None, layer:bool = False, - boxsize:float=None, fixfirst:bool = False, seed:float=None, _binary_name="ran_box", verbose=False, return_command_only=False)->str: + def ran_box( + self, + in_top_path: str, + in_cnf_path: str, + out_cnf_path: str = "", + periodic_boundary_condition: str = "r", + nmolecule: int = 1, + dens: float = 1.0, + threshold: float = None, + layer: bool = False, + boxsize: float = None, + fixfirst: bool = False, + seed: float = None, + _binary_name="ran_box", + verbose=False, + return_command_only=False, + ) -> str: command_suffix = "" - if(out_cnf_path== ""): - out_cnf_path = os.path.dirname(in_cnf_path) + "/" + str(os.path.splitext(os.path.basename(in_cnf_path))[0]) + "_ran-box.cnf" - if(threshold!=None): - command_suffix+= " @thresh " + str(threshold) + if out_cnf_path == "": + out_cnf_path = ( + os.path.dirname(in_cnf_path) + + "/" + + str(os.path.splitext(os.path.basename(in_cnf_path))[0]) + + "_ran-box.cnf" + ) + if threshold != None: + command_suffix += " @thresh " + str(threshold) if layer: command_suffix += " @layer " - if(boxsize!=None): - command_suffix+= " @boxsize "+ str(boxsize) + if boxsize != None: + command_suffix += " @boxsize " + str(boxsize) if fixfirst: command_suffix += " @fixfirst " - if(seed!=None): - command_suffix+= " @seed " + str(seed) - - - command= self._bin + _binary_name + " @topo " + in_top_path + " @pbc " + periodic_boundary_condition + " @pos " + in_cnf_path + " @nsm " + str(nmolecule) + " @dens " + str(dens) + " " + command_suffix + " > " + out_cnf_path + " \n" + if seed != None: + command_suffix += " @seed " + str(seed) + + command = ( + self._bin + + _binary_name + + " @topo " + + in_top_path + + " @pbc " + + periodic_boundary_condition + + " @pos " + + in_cnf_path + + " @nsm " + + str(nmolecule) + + " @dens " + + str(dens) + + " " + + command_suffix + + " > " + + out_cnf_path + + " \n" + ) if not return_command_only: print(command) std_out = bash.execute(command, verbose=verbose) @@ -705,13 +945,42 @@ def ran_box(self, in_top_path:str, in_cnf_path:str, out_cnf_path:str= "", return command @gromosTypeConverter - def build_box(self, in_top_path:str, in_cnf_path:str, out_cnf_path:str= "", - periodic_boundary_condition: str = "r", nmolecule:int = 1, dens:float = 1.0, _binary_name="build_box", verbose=False, return_command_only=False)->str: - - if(out_cnf_path== ""): - out_cnf_path = os.path.dirname(in_cnf_path) + "/" + str(os.path.splitext(os.path.basename(in_cnf_path))[0]) + "_ran-box.cnf" - - command= self._bin + _binary_name + " @topo " + in_top_path + " @pos " + in_cnf_path + " @nsm " + str(nmolecule) + " @dens " + str(dens) + " > " + out_cnf_path + " \n" + def build_box( + self, + in_top_path: str, + in_cnf_path: str, + out_cnf_path: str = "", + periodic_boundary_condition: str = "r", + nmolecule: int = 1, + dens: float = 1.0, + _binary_name="build_box", + verbose=False, + return_command_only=False, + ) -> str: + + if out_cnf_path == "": + out_cnf_path = ( + os.path.dirname(in_cnf_path) + + "/" + + str(os.path.splitext(os.path.basename(in_cnf_path))[0]) + + "_ran-box.cnf" + ) + + command = ( + self._bin + + _binary_name + + " @topo " + + in_top_path + + " @pos " + + in_cnf_path + + " @nsm " + + str(nmolecule) + + " @dens " + + str(dens) + + " > " + + out_cnf_path + + " \n" + ) if not return_command_only: print(command) std_out = bash.execute(command, verbose=verbose) @@ -720,10 +989,20 @@ def build_box(self, in_top_path:str, in_cnf_path:str, out_cnf_path:str= "", return command @gromosTypeConverter - def tser(self, in_trc_path:str, in_top_path:str, out_csv_path:str, property:str, - periodic_boundary_condition:str= "r", time:float = None, solvent:str=None, - normalise_distribution:bool=False, skip_first_n_frames:int=0, take_each_nth_frame:int=1, - _binary_name:str= "tser")->str: + def tser( + self, + in_trc_path: str, + in_top_path: str, + out_csv_path: str, + property: str, + periodic_boundary_condition: str = "r", + time: float = None, + solvent: str = None, + normalise_distribution: bool = False, + skip_first_n_frames: int = 0, + take_each_nth_frame: int = 1, + _binary_name: str = "tser", + ) -> str: """ Tser is a gromos programm, that can analyze trajectories. @@ -751,23 +1030,39 @@ def tser(self, in_trc_path:str, in_top_path:str, out_csv_path:str, property:str, out_csv_path """ optional_string = "" - if(take_each_nth_frame > 1): - optional_string += " @stride "+str(take_each_nth_frame)+" " - if(skip_first_n_frames>0): - optional_string += " @skip "+str(skip_first_n_frames)+" " - if(normalise_distribution): + if take_each_nth_frame > 1: + optional_string += " @stride " + str(take_each_nth_frame) + " " + if skip_first_n_frames > 0: + optional_string += " @skip " + str(skip_first_n_frames) + " " + if normalise_distribution: optional_string += " @norm " - if(isinstance(time, type(None))): - optional_string += " @time "+str(time)+" " - if(isinstance(solvent, type(None))): - optional_string += " @solv "+str(solvent)+" " - - command = self._bin + _binary_name + " @topo " + in_top_path + " @pbc " + periodic_boundary_condition + " @traj " + in_trc_path + " @prop \"" + str(property) + "\" " + optional_string + " > " + out_csv_path +" \n" + if isinstance(time, type(None)): + optional_string += " @time " + str(time) + " " + if isinstance(solvent, type(None)): + optional_string += " @solv " + str(solvent) + " " + + command = ( + self._bin + + _binary_name + + " @topo " + + in_top_path + + " @pbc " + + periodic_boundary_condition + + " @traj " + + in_trc_path + + ' @prop "' + + str(property) + + '" ' + + optional_string + + " > " + + out_csv_path + + " \n" + ) bash.execute(command) return out_csv_path @gromosTypeConverter - def red_top(self, in_top_path:str, atom_selection:str, out_top_path:str, _binary_name:str= "red_top")->str: + def red_top(self, in_top_path: str, atom_selection: str, out_top_path: str, _binary_name: str = "red_top") -> str: """ red_top is a gromos tool to reduce a gromos tool to a certain selection. Parameters @@ -783,13 +1078,28 @@ def red_top(self, in_top_path:str, atom_selection:str, out_top_path:str, _binary out_top_path """ - command = [self._bin + _binary_name, " @topo ", in_top_path, " @atoms", "'" + atom_selection + "'", "> " + out_top_path + " \n"] + command = [ + self._bin + _binary_name, + " @topo ", + in_top_path, + " @atoms", + "'" + atom_selection + "'", + "> " + out_top_path + " \n", + ] bash.execute(command) return out_top_path @gromosTypeConverter - def prep_eds(self, in_top_paths:List[str], number_of_eds_states:int, param_top_index:int=1, solv_top_index:int=1, - out_file_path:str= "dev", _binary_name:str= "prep_eds", verbose:bool=False)->(str, str): + def prep_eds( + self, + in_top_paths: List[str], + number_of_eds_states: int, + param_top_index: int = 1, + solv_top_index: int = 1, + out_file_path: str = "dev", + _binary_name: str = "prep_eds", + verbose: bool = False, + ) -> (str, str): """ prepare eds topology. @@ -810,17 +1120,28 @@ def prep_eds(self, in_top_paths:List[str], number_of_eds_states:int, param_top_i out_top, out_ptp """ out_file_path = os.path.splitext(out_file_path)[0] - if(type(in_top_paths) == str): + if type(in_top_paths) == str: in_top_paths = [in_top_paths] - if(len(in_top_paths) == 0): + if len(in_top_paths) == 0: raise ValueError("no topos were passed to function. please provide at least two") - command = self._bin + _binary_name + " @topo " + " ".join(in_top_paths) + " @numstat " + str(number_of_eds_states) + " @param " + str(param_top_index) + " @solv " + str(solv_top_index) - if(verbose): + command = ( + self._bin + + _binary_name + + " @topo " + + " ".join(in_top_paths) + + " @numstat " + + str(number_of_eds_states) + + " @param " + + str(param_top_index) + + " @solv " + + str(solv_top_index) + ) + if verbose: print(command) ret = bash.execute(command) - if(verbose): + if verbose: print(ret.readlines()) bash.wait_for_fileSystem(["./pert_eds.ptp", "./com_eds.top"]) @@ -831,11 +1152,19 @@ def prep_eds(self, in_top_paths:List[str], number_of_eds_states:int, param_top_i return out_top, out_ptp @gromosTypeConverter - def prep_noe(self, in_top_path:str, in_noe_path:str, in_library_path:str, out_path:str, - dish:float=0.1, disc:float=0.153, - title:str="NOE", _binary_name:str= "prep_noe", - in_correction_path: str = None, - verbose:bool=False)->str: + def prep_noe( + self, + in_top_path: str, + in_noe_path: str, + in_library_path: str, + out_path: str, + dish: float = 0.1, + disc: float = 0.153, + title: str = "NOE", + _binary_name: str = "prep_noe", + in_correction_path: str = None, + verbose: bool = False, + ) -> str: """ Parameters @@ -866,9 +1195,9 @@ def prep_noe(self, in_top_path:str, in_noe_path:str, in_library_path:str, out_pa ------- parsetype: <1,2,3> Choices are: - 1: Upper bound == first number - 2: Upper bound == first + third number (most common, default) - 3: Upper bound == first - second number (commonly the lower bound) + 1: Upper bound == first number + 2: Upper bound == first + third number (most common, default) + 3: Upper bound == first - second number (commonly the lower bound) action: or = add filter: discard nNOE's above a certain distance[nm] = 10000 nm factor: conversion factor ang to nm , = 10 @@ -876,20 +1205,42 @@ def prep_noe(self, in_top_path:str, in_noe_path:str, in_library_path:str, out_pa """ additional_options = "" - if(isinstance(in_correction_path, str)): - additional_options += "@correction "+in_correction_path+" " - - command = self._bin + _binary_name + " @topo " + in_top_path + " @title " + title +" @noe " + in_noe_path +" @lib " + in_library_path + " " \ - " @dish " + str(dish) +" @disc " + str(disc) +" " + additional_options +" &> " + out_path - - if (verbose): print(command) + if isinstance(in_correction_path, str): + additional_options += "@correction " + in_correction_path + " " + + command = ( + self._bin + + _binary_name + + " @topo " + + in_top_path + + " @title " + + title + + " @noe " + + in_noe_path + + " @lib " + + in_library_path + + " " + " @dish " + str(dish) + " @disc " + str(disc) + " " + additional_options + " &> " + out_path + ) + + if verbose: + print(command) ret = bash.execute(command) - if (verbose): print(ret.readlines()) + if verbose: + print(ret.readlines()) return out_path @gromosTypeConverter - def rmsf(self, in_top_path:str, in_trcs:Union[str, List[str]], atom_selection:str, out_file_path:str, pbc: str= "r", _binary_name:str= "rmsf")->str: + def rmsf( + self, + in_top_path: str, + in_trcs: Union[str, List[str]], + atom_selection: str, + out_file_path: str, + pbc: str = "r", + _binary_name: str = "rmsf", + ) -> str: """ this is a wrapper for gromosPP rmsf programm. (Root mean square fluctuation @@ -914,18 +1265,40 @@ def rmsf(self, in_top_path:str, in_trcs:Union[str, List[str]], atom_selection:st outpath of the traj """ - if(isinstance(in_trcs, list)): + if isinstance(in_trcs, list): in_trcs = " ".join(in_trcs) additional_options = [""] additional_options = " ".join(map(str, additional_options)) - command = " ".join([self._bin + _binary_name, " @topo ", in_top_path, " @atomsrmsf", "'" + atom_selection + "'", "@pbc", pbc, "@traj", in_trcs, additional_options, " \n"]) + command = " ".join( + [ + self._bin + _binary_name, + " @topo ", + in_top_path, + " @atomsrmsf", + "'" + atom_selection + "'", + "@pbc", + pbc, + "@traj", + in_trcs, + additional_options, + " \n", + ] + ) bash.execute(command, catch_STD=out_file_path) return out_file_path @gromosTypeConverter - def rmsd(self, in_top_path:str, in_trcs:Union[str, List[str]], atom_selection:str, out_file_path:str, pbc: str= "r", _binary_name:str= "rmsd")->str: + def rmsd( + self, + in_top_path: str, + in_trcs: Union[str, List[str]], + atom_selection: str, + out_file_path: str, + pbc: str = "r", + _binary_name: str = "rmsd", + ) -> str: """ Parameters @@ -942,23 +1315,48 @@ def rmsd(self, in_top_path:str, in_trcs:Union[str, List[str]], atom_selection:st """ - if(isinstance(in_trcs, list)): + if isinstance(in_trcs, list): in_trcs = " ".join(in_trcs) additional_options = [""] additional_options = " ".join(map(str, additional_options)) - command = " ".join([self._bin + _binary_name, " @topo ", in_top_path, " @atomsrmsd", "'" + atom_selection + "'", "@pbc", pbc, "@traj", in_trcs, additional_options, " \n"]) + command = " ".join( + [ + self._bin + _binary_name, + " @topo ", + in_top_path, + " @atomsrmsd", + "'" + atom_selection + "'", + "@pbc", + pbc, + "@traj", + in_trcs, + additional_options, + " \n", + ] + ) bash.execute(command, catch_STD=out_file_path) return out_file_path @gromosTypeConverter - def cog(self, in_top_path:str, in_trcs:Union[str, List[str]], out_file_path:str, - atom_selection:str=None, outformat:str=None, cog_com:str=None, - add_repl:str=None, solv:str=None, nthframe:str=None, - pbc: str="r cog", _binary_name:str= "cog", verbose:bool=False)->str: + def cog( + self, + in_top_path: str, + in_trcs: Union[str, List[str]], + out_file_path: str, + atom_selection: str = None, + outformat: str = None, + cog_com: str = None, + add_repl: str = None, + solv: str = None, + nthframe: str = None, + pbc: str = "r cog", + _binary_name: str = "cog", + verbose: bool = False, + ) -> str: """ - + Parameters ---------- in_top_path : str @@ -988,36 +1386,47 @@ def cog(self, in_top_path:str, in_trcs:Union[str, List[str]], out_file_path:str, output_path of the generated csv file """ - if (isinstance(in_trcs, list)): + if isinstance(in_trcs, list): in_trcs = " ".join(in_trcs) additional_options = [""] - if(not atom_selection is None): - additional_options+= [" @atomspec ", "'" + atom_selection + "'"] - if(not outformat is None): - additional_options+= [" @outformat ", outformat ] - if(not cog_com is None): - additional_options+= [" @cog_com ", cog_com ] - if(not add_repl is None): + if not atom_selection is None: + additional_options += [" @atomspec ", "'" + atom_selection + "'"] + if not outformat is None: + additional_options += [" @outformat ", outformat] + if not cog_com is None: + additional_options += [" @cog_com ", cog_com] + if not add_repl is None: additional_options += [" @add_repl ", add_repl] - if(not solv is None): + if not solv is None: additional_options += [" @solv ", solv] - if(not nthframe is None): + if not nthframe is None: additional_options += [" @nthframe ", nthframe] additional_options = " ".join(map(str, additional_options)) - command = " ".join([self._bin + _binary_name, " @topo ", in_top_path, "@pbc", pbc, "@traj", in_trcs, additional_options, " \n"]) + command = " ".join( + [self._bin + _binary_name, " @topo ", in_top_path, "@pbc", pbc, "@traj", in_trcs, additional_options, " \n"] + ) - if(verbose): print(command) + if verbose: + print(command) bash.execute(command, catch_STD=out_file_path, verbose=verbose) return out_file_path @gromosTypeConverter - def noe(self, in_top_path:str, in_noe_path:str, in_traj_path:str, out_path:str, - pbc:str="v", gathering:str="cog", - _binary_name:str= "noe", verbose:bool=False) -> str: + def noe( + self, + in_top_path: str, + in_noe_path: str, + in_traj_path: str, + out_path: str, + pbc: str = "v", + gathering: str = "cog", + _binary_name: str = "noe", + verbose: bool = False, + ) -> str: """ Parameters @@ -1050,18 +1459,43 @@ def noe(self, in_top_path:str, in_noe_path:str, in_traj_path:str, out_path:str, --------------- time: float, float (time, dt) """ - command = self._bin + _binary_name + " @topo " + in_top_path + " @traj "+in_traj_path+" @noe "+in_noe_path+" @pbc "+str(pbc)+" "+str(gathering)+"\n" - - if (verbose): print(command) + command = ( + self._bin + + _binary_name + + " @topo " + + in_top_path + + " @traj " + + in_traj_path + + " @noe " + + in_noe_path + + " @pbc " + + str(pbc) + + " " + + str(gathering) + + "\n" + ) + + if verbose: + print(command) p = bash.execute(command, catch_STD=out_path, verbose=verbose) return out_path @gromosTypeConverter - def jval(self, in_top_path:str, in_jval_path:str, in_traj_path:(str, List[str]), out_path:str, - pbc:str="v", gathering:str="cog", - timeseries:bool=False, rmsd:bool = False, time:float = None, - _binary_name:str= "jval", verbose:bool=False): + def jval( + self, + in_top_path: str, + in_jval_path: str, + in_traj_path: (str, List[str]), + out_path: str, + pbc: str = "v", + gathering: str = "cog", + timeseries: bool = False, + rmsd: bool = False, + time: float = None, + _binary_name: str = "jval", + verbose: bool = False, + ): """ Parameters @@ -1101,33 +1535,60 @@ def jval(self, in_top_path:str, in_jval_path:str, in_traj_path:(str, List[str]) time: float, float (time, dt) """ - additional_options= "" - if(timeseries): + additional_options = "" + if timeseries: additional_options += " @timeseries " - if(rmsd): + if rmsd: additional_options += " @rmsd " - if(isinstance(time, (Number, str))): - additional_options += " @time "+str(time)+" " + if isinstance(time, (Number, str)): + additional_options += " @time " + str(time) + " " - if(isinstance(in_traj_path, List)): + if isinstance(in_traj_path, List): in_traj_path = "\n".join(in_traj_path) - command = self._bin + _binary_name + " @topo " + in_top_path + " @traj "+in_traj_path+" @jval "+in_jval_path+" @pbc "+str(pbc)+" "+str(gathering)+" "+additional_options+" &> "+out_path - - if (verbose): print(command) + command = ( + self._bin + + _binary_name + + " @topo " + + in_top_path + + " @traj " + + in_traj_path + + " @jval " + + in_jval_path + + " @pbc " + + str(pbc) + + " " + + str(gathering) + + " " + + additional_options + + " &> " + + out_path + ) + + if verbose: + print(command) ret = bash.execute(command) - if (verbose): print(ret.readlines()) + if verbose: + print(ret.readlines()) return out_path @gromosTypeConverter - def ion(self, in_top_path:str,in_cnf_path:str, out_cnf_path:str, - periodic_boundary_condition:str="v", - negative:list=None, positive:list=None, - potential:float=0.8, mindist:float=0.8, - random_seed: int=None, exclude:str=None, - _binary_name = "ion", verbose:bool=False - )->str: + def ion( + self, + in_top_path: str, + in_cnf_path: str, + out_cnf_path: str, + periodic_boundary_condition: str = "v", + negative: list = None, + positive: list = None, + potential: float = 0.8, + mindist: float = 0.8, + random_seed: int = None, + exclude: str = None, + _binary_name="ion", + verbose: bool = False, + ) -> str: """ When simulating a charged solute in solution, one may wish to include counter-ions in the molecular system in order to obtain a neutral system, or @@ -1175,40 +1636,60 @@ def ion(self, in_top_path:str,in_cnf_path:str, out_cnf_path:str, returns the resulting cnf-file path """ optional_args = [] - if(not positive is None): - opt = "@positive "+" ".join(map(str, positive)) + if not positive is None: + opt = "@positive " + " ".join(map(str, positive)) optional_args.append(opt) - if(not negative is None): - opt = "@negative "+" ".join(map(str, negative)) + if not negative is None: + opt = "@negative " + " ".join(map(str, negative)) optional_args.append(opt) - if(not random_seed is None): - opt = "@random "+" ".join(map(str, random_seed)) + if not random_seed is None: + opt = "@random " + " ".join(map(str, random_seed)) optional_args.append(opt) - if(not exclude is None): - opt = "@exclude "+" ".join(map(str, exclude)) + if not exclude is None: + opt = "@exclude " + " ".join(map(str, exclude)) optional_args.append(opt) - - command = self._bin + _binary_name + " @topo " + in_top_path + " @pos " + in_cnf_path + " @pbc " + periodic_boundary_condition+" " - command+= "@potential "+str(potential)+" @mindist "+str(mindist)+" "+" ".join(optional_args) - - if(verbose): print(command) + command = ( + self._bin + + _binary_name + + " @topo " + + in_top_path + + " @pos " + + in_cnf_path + + " @pbc " + + periodic_boundary_condition + + " " + ) + command += "@potential " + str(potential) + " @mindist " + str(mindist) + " " + " ".join(optional_args) + + if verbose: + print(command) bash.execute(command, catch_STD=out_cnf_path) return out_cnf_path - #To implement + # To implement def _gr962pdb(self): - raise Exception('not implemented yet!') + raise Exception("not implemented yet!") @gromosTypeConverter - def rgyr(self, out_rgyr_path:str, in_coord_path:str, in_top_path:str, atom_selection:str="1:a", periodic_boundary_condition:str="r cog", time:int=None, dt:int=None, - mass_weighted:bool=False, _binary_name:str= "rgyr")->str: + def rgyr( + self, + out_rgyr_path: str, + in_coord_path: str, + in_top_path: str, + atom_selection: str = "1:a", + periodic_boundary_condition: str = "r cog", + time: int = None, + dt: int = None, + mass_weighted: bool = False, + _binary_name: str = "rgyr", + ) -> str: """ - This wrapper uses rgyr to compute the radius of gyration for a given atom selection. + This wrapper uses rgyr to compute the radius of gyration for a given atom selection. Parameters ---------- @@ -1219,8 +1700,8 @@ def rgyr(self, out_rgyr_path:str, in_coord_path:str, in_top_path:str, atom_selec periodic_boundary_condition: str, optional time: int, optional dt: int, optional - mass_weighted:bool, optional - _binary_name: str, optional + mass_weighted:bool, optional + _binary_name: str, optional Returns ------- @@ -1232,27 +1713,40 @@ def rgyr(self, out_rgyr_path:str, in_coord_path:str, in_top_path:str, atom_selec For more information checkout the Gromos Manual """ - args = ["@topo " + in_top_path, - "@pbc " + periodic_boundary_condition, - "@atoms " + atom_selection, - "@traj " + in_coord_path] - - if(not isinstance(time, type(None))): - args += "@time "+str(time)+" " - if(not isinstance(time, type(None)) and not isinstance(dt, type(None))): - args += " "+str(dt)+" " - if(not isinstance(mass_weighted, type(False))): + args = [ + "@topo " + in_top_path, + "@pbc " + periodic_boundary_condition, + "@atoms " + atom_selection, + "@traj " + in_coord_path, + ] + + if not isinstance(time, type(None)): + args += "@time " + str(time) + " " + if not isinstance(time, type(None)) and not isinstance(dt, type(None)): + args += " " + str(dt) + " " + if not isinstance(mass_weighted, type(False)): args += "@massweighted " - - command = self._bin +_binary_name+" "+" ".join(args) + + command = self._bin + _binary_name + " " + " ".join(args) bash.execute(command, catch_STD=out_rgyr_path) return out_rgyr_path - @gromosTypeConverter - def sasa(self, out_sasa_path:str, in_coord_path:str, in_top_path:str, atom_selection:str="1:a", sasa_atoms:str="1:a", - probe:str="4 1.4", periodic_boundary_condition:str="r cog", zslice:float=None, time:int=None, dt:int=None, - verbose:bool=False, _binary_name:str= "sasa")->str: + def sasa( + self, + out_sasa_path: str, + in_coord_path: str, + in_top_path: str, + atom_selection: str = "1:a", + sasa_atoms: str = "1:a", + probe: str = "4 1.4", + periodic_boundary_condition: str = "r cog", + zslice: float = None, + time: int = None, + dt: int = None, + verbose: bool = False, + _binary_name: str = "sasa", + ) -> str: """ This wrapper uses sasa to compute the solvent accessible surface area (SASA) for a given atom selection. By default, this is done for the first residue (1:a) with parameters for water (IAC type: 4, radius: 0.4 nm) @@ -1270,7 +1764,7 @@ def sasa(self, out_sasa_path:str, in_coord_path:str, in_top_path:str, atom_selec time: int, optional dt: int, optional verbose: bool, optional - _binary_name: str, optional + _binary_name: str, optional Returns ------- @@ -1282,30 +1776,45 @@ def sasa(self, out_sasa_path:str, in_coord_path:str, in_top_path:str, atom_selec For more information checkout the Gromos Manual """ - args = ["@topo " + in_top_path, - "@pbc " + periodic_boundary_condition, - "@atoms " + atom_selection, - "@sasaatoms " + sasa_atoms, - "@probe " + probe, - "@traj " + in_coord_path] - - if(not isinstance(time, type(None))): - args += "@time "+str(time)+" " - if(not isinstance(time, type(None)) and not isinstance(dt, type(None))): - args += " "+str(dt)+" " - if(not isinstance(zslice, type(None))): - args += "@zslice "+zslice+" " - if(not isinstance(verbose, type(False))): + args = [ + "@topo " + in_top_path, + "@pbc " + periodic_boundary_condition, + "@atoms " + atom_selection, + "@sasaatoms " + sasa_atoms, + "@probe " + probe, + "@traj " + in_coord_path, + ] + + if not isinstance(time, type(None)): + args += "@time " + str(time) + " " + if not isinstance(time, type(None)) and not isinstance(dt, type(None)): + args += " " + str(dt) + " " + if not isinstance(zslice, type(None)): + args += "@zslice " + zslice + " " + if not isinstance(verbose, type(False)): args += "@verbose " - - command = self._bin +_binary_name+" "+" ".join(args) + + command = self._bin + _binary_name + " " + " ".join(args) bash.execute(command, catch_STD=out_sasa_path) return out_sasa_path @gromosTypeConverter - def filter(self, out_filter_path:str, in_coord_path:str, in_top_path:str, atom_selection:str=None, - periodic_boundary_condition:str="r cog", cutoff:float=None, pairlist:str=None, select:str="1:a", reject:str=None, - time:int=None, dt:int=None, outformat:str=None, _binary_name:str= "filter")->str: + def filter( + self, + out_filter_path: str, + in_coord_path: str, + in_top_path: str, + atom_selection: str = None, + periodic_boundary_condition: str = "r cog", + cutoff: float = None, + pairlist: str = None, + select: str = "1:a", + reject: str = None, + time: int = None, + dt: int = None, + outformat: str = None, + _binary_name: str = "filter", + ) -> str: """ This wrapper uses filter to reduce a given trajectory to a selection of atoms. By default, only the first residue (1:a) is retained. @@ -1323,7 +1832,7 @@ def filter(self, out_filter_path:str, in_coord_path:str, in_top_path:str, atom_s time: int, optional dt: int, optional outformat: str, optional - _binary_name: str, optional + _binary_name: str, optional Returns ------- @@ -1335,25 +1844,26 @@ def filter(self, out_filter_path:str, in_coord_path:str, in_top_path:str, atom_s For more information checkout the Gromos Manual """ - args = [f"@topo {in_top_path} ", - f"@pbc {periodic_boundary_condition} ", - f"@traj {in_coord_path} ", - f"@select {select} "] + args = [ + f"@topo {in_top_path} ", + f"@pbc {periodic_boundary_condition} ", + f"@traj {in_coord_path} ", + f"@select {select} ", + ] - - if(not isinstance(cutoff, type(None))): + if not isinstance(cutoff, type(None)): args += f"@cutoff {cutoff} " - if(not isinstance(pairlist, type(None))): + if not isinstance(pairlist, type(None)): args += f"@pairlist {pairlist} " - if(not isinstance(atom_selection, type(None))): + if not isinstance(atom_selection, type(None)): args += f"@atoms {atom_selection} " - if(not isinstance(reject, type(None))): + if not isinstance(reject, type(None)): args += f"@reject {reject} " - if(not isinstance(time, type(None))): + if not isinstance(time, type(None)): args += f" @time {time} " - if(not isinstance(time, type(None)) and not isinstance(dt, type(None))): + if not isinstance(time, type(None)) and not isinstance(dt, type(None)): args += f"{dt} " - if(not isinstance(outformat, type(None))): + if not isinstance(outformat, type(None)): args += f" @outformat {outformat} " args_str = "".join(args) @@ -1374,5 +1884,5 @@ class GromosPP(_gromosPPbase): This is the path to the folder containing the binaries of gromosPP If None, the bash enviroment variables will be used. """ - def __init__(self, gromosPP_bin_dir: str =None): + def __init__(self, gromosPP_bin_dir: str = None): super().__init__(gromosPP_bin_dir=gromosPP_bin_dir) diff --git a/pygromos/gromos/gromosXX.py b/pygromos/gromos/gromosXX.py index be2eabc6..b2722de4 100644 --- a/pygromos/gromos/gromosXX.py +++ b/pygromos/gromos/gromosXX.py @@ -15,6 +15,7 @@ from pygromos.utils.utils import time_wait_s_for_filesystem from pygromos.gromos.utils import gromosTypeConverter + class _Gromos: """ GromosXX @@ -26,6 +27,7 @@ class _Gromos: bin : str, optional This is the path to the folder containing the binaries of gromosXX. If None, the bash enviroment variables will be used. """ + _bin: str = "" def __init__(self, gromosXX_bin_dir: str = None): @@ -37,34 +39,52 @@ def __init__(self, gromosXX_bin_dir: str = None): gromosXX_bin_dir : str, optional This is the path to the folder containing the binaries of gromosXX. If None, the bash enviroment variables will be used. """ - #lazy me - doc text for functions: - functions_text = "\n Methods:\n ---------\n" + "\n".join(["\t" + x for x in dir(self) if (not x.startswith("_") and callable(getattr(self, x)))]) - self.__doc__ = self.__doc__+functions_text + # lazy me - doc text for functions: + functions_text = "\n Methods:\n ---------\n" + "\n".join( + ["\t" + x for x in dir(self) if (not x.startswith("_") and callable(getattr(self, x)))] + ) + self.__doc__ = self.__doc__ + functions_text - if (isinstance(gromosXX_bin_dir, type(None)) or gromosXX_bin_dir == "None"): + if isinstance(gromosXX_bin_dir, type(None)) or gromosXX_bin_dir == "None": self._bin = "" else: self._bin = gromosXX_bin_dir + "/" def __str__(self): return self.__doc__ + def __repr__(self): return self.__str__() @property - def bin(self)->Union[str, None]: - if(not hasattr(self, "_bin") or self._bin == ""): + def bin(self) -> Union[str, None]: + if not hasattr(self, "_bin") or self._bin == "": return None else: return self._bin @gromosTypeConverter - def md_run(self, in_topo_path: str, in_coord_path: str, in_imd_path: str, out_prefix: str, - in_pert_topo_path:str=None, in_disres_path:str=None, in_posresspec_path:str=None, in_refpos_path:str=None, - in_qmmm_path:str=None, nomp: int = 1, nmpi: int = 1, - out_trc: bool = False, out_tre: bool = False, out_trv: bool = False, out_trf: bool = False, - out_trs: bool = False, out_trg:bool = False, - verbose:bool = False) -> str: + def md_run( + self, + in_topo_path: str, + in_coord_path: str, + in_imd_path: str, + out_prefix: str, + in_pert_topo_path: str = None, + in_disres_path: str = None, + in_posresspec_path: str = None, + in_refpos_path: str = None, + in_qmmm_path: str = None, + nomp: int = 1, + nmpi: int = 1, + out_trc: bool = False, + out_tre: bool = False, + out_trv: bool = False, + out_trf: bool = False, + out_trs: bool = False, + out_trg: bool = False, + verbose: bool = False, + ) -> str: """ This function is a wrapper for gromosXX md_mpi. You can directly execute the gromosXX md_mpi in a bash enviroment here. @@ -133,14 +153,14 @@ def md_run(self, in_topo_path: str, in_coord_path: str, in_imd_path: str, out_pr """ - #BUILD UP str. Command + # BUILD UP str. Command command = [] - if(nmpi > 1 and nomp > 1): + if nmpi > 1 and nomp > 1: raise ValueError("There are no Hybrid NMPI and NOMP jobs possible with gromos!") - elif(nmpi > 1): - command += ["mpirun -n " + str(nmpi*nomp)+" "] # --loadbalance " --cpus-per-proc " + + " " + elif nmpi > 1: + command += ["mpirun -n " + str(nmpi * nomp) + " "] # --loadbalance " --cpus-per-proc " + + " " command += [self._bin + "md_mpi"] - elif(nomp >= 1): + elif nomp >= 1: command += ["export OMP_NUM_THREADS=" + str(nomp) + " && "] command += [self._bin + "md"] else: @@ -183,24 +203,25 @@ def md_run(self, in_topo_path: str, in_coord_path: str, in_imd_path: str, out_pr if out_trg: command += ["@trg", str(out_prefix) + ".trg"] else: - raise ValueError("Outprefix needs to be string got: "+type(out_prefix)+" - "+str(out_prefix)) + raise ValueError("Outprefix needs to be string got: " + type(out_prefix) + " - " + str(out_prefix)) command_text = " ".join(command) + " > " + log_file_path + "\n" - if verbose: print("COMMAND: ", command_text) + if verbose: + print("COMMAND: ", command_text) start_time = datetime.datetime.now() process = bash.execute(command_text) md_run_return = process.poll() - #bash.wait_for_fileSystem(out_prefix+".cnf") + # bash.wait_for_fileSystem(out_prefix+".cnf") end_time = datetime.datetime.now() - duration = end_time-start_time + duration = end_time - start_time time.sleep(time_wait_s_for_filesystem) log_file = open(log_file_path, "a") log_file.write("\n\nREMARKS\n") failed = False - if (md_run_return == 0): + if md_run_return == 0: log_file.write("\tRUN:\tSUCESSFUL\n") else: log_file.write("\tRUN:\tFAILED\n") @@ -211,16 +232,30 @@ def md_run(self, in_topo_path: str, in_coord_path: str, in_imd_path: str, out_pr log_file.write("END\n") log_file.close() - if (md_run_return!=0): + if md_run_return != 0: raise ChildProcessError("GromosXX MD Run Failed!\n\nLOG:" + "\n".join(open(log_file_path, "r").readlines())) return log_file_path @gromosTypeConverter - def repex_run(self, in_topo_path: str, in_coord_path: str, in_imd_path: str, out_prefix: str, - in_pert_topo_path: str = None, in_disres_path: str = None, in_posresspec_path: bool = False, in_refpos_path: bool = False, - out_trc: bool = True, out_tre: bool = True, out_trs: bool = False, out_trg:bool = False, - nomp: int = 1, nmpi: int = 1, verbose: bool = True) -> str: + def repex_run( + self, + in_topo_path: str, + in_coord_path: str, + in_imd_path: str, + out_prefix: str, + in_pert_topo_path: str = None, + in_disres_path: str = None, + in_posresspec_path: bool = False, + in_refpos_path: bool = False, + out_trc: bool = True, + out_tre: bool = True, + out_trs: bool = False, + out_trg: bool = False, + nomp: int = 1, + nmpi: int = 1, + verbose: bool = True, + ) -> str: """ This function is a wrapper for gromosXX repex_mpi. You can directly execute the gromosXX repex_mpi in a bash enviroment here. @@ -291,8 +326,16 @@ def repex_run(self, in_topo_path: str, in_coord_path: str, in_imd_path: str, out """ - if (nomp > 1): # OMP Hybrid sopt_job? - command = ["export OMP_NUM_THREADS=" + str(nomp) + " && mpirun -n " + str(nmpi) + " --loadbalance --cpus-per-proc " + str(nomp) + " "] + if nomp > 1: # OMP Hybrid sopt_job? + command = [ + "export OMP_NUM_THREADS=" + + str(nomp) + + " && mpirun -n " + + str(nmpi) + + " --loadbalance --cpus-per-proc " + + str(nomp) + + " " + ] else: command = ["mpirun", "-n ", str(nmpi)] @@ -344,26 +387,30 @@ def repex_run(self, in_topo_path: str, in_coord_path: str, in_imd_path: str, out log_file_path = out_prefix + ".omd" command_text = " ".join(command) + " >> " + log_file_path + "\n" - if verbose: print(command_text) + if verbose: + print(command_text) - os.system("echo \"\" >" + str(log_file_path)) + os.system('echo "" >' + str(log_file_path)) - if verbose: start_time = time.ctime() - if verbose: print("START: " + str(start_time)) + if verbose: + start_time = time.ctime() + if verbose: + print("START: " + str(start_time)) - #bash.execute(command, verbose=True) + # bash.execute(command, verbose=True) md_run = os.system(command_text) time.sleep(time_wait_s_for_filesystem) - if verbose: end_time = time.ctime() - if verbose: print("END: " + str(end_time)) + if verbose: + end_time = time.ctime() + if verbose: + print("END: " + str(end_time)) print("MDRUN OUT: ", md_run) - #if (md_run != 0): + # if (md_run != 0): # raise ChildProcessError("GromosXX REPEX Run Failed!\n \t return value: " + str(md_run) + "\n\tLOG:" + "\n\t\t".join(open(log_file_path, "r").readlines())) return log_file_path - class GromosXX(_Gromos): """ GromosXX diff --git a/pygromos/gromos/pyGromosPP/com_top.py b/pygromos/gromos/pyGromosPP/com_top.py index 0879f62a..99e364a1 100644 --- a/pygromos/gromos/pyGromosPP/com_top.py +++ b/pygromos/gromos/pyGromosPP/com_top.py @@ -1,7 +1,7 @@ -""" +""" COM_TOP -Python version of the GROMOS++ program to combine two topologies. +Python version of the GROMOS++ program to combine two topologies. All molecules are combined to a single topology and it can be decided where the solvent and parameters ar taken from. This mehod can also be called directly via top1.com_top(top2), top1 + top2 or top1+=top2 @@ -12,9 +12,17 @@ from typing import List from pygromos.files.topology.top import Top -def com_top(top1:Top, top2:Top, topo_multiplier:List[int]=[1,1], solvFrom1:bool=True, paramFrom1:bool=True, verbose:bool=True) -> Top: + +def com_top( + top1: Top, + top2: Top, + topo_multiplier: List[int] = [1, 1], + solvFrom1: bool = True, + paramFrom1: bool = True, + verbose: bool = True, +) -> Top: """ - Python version of the GROMOS++ program to combine two topologies. + Python version of the GROMOS++ program to combine two topologies. All molecules are combined to a single topology and it can be decided where the solvent and parameters ar taken from. This mehod can also be called directly via top1.com_top(top2), top1 + top2 or top1+=top2 @@ -48,14 +56,16 @@ def com_top(top1:Top, top2:Top, topo_multiplier:List[int]=[1,1], solvFrom1:bool= raise Exception("Does not work with negative multipliers") # create the return top - retTop=Top(in_value=None) - + retTop = Top(in_value=None) + if paramFrom1: retTop = top1.multiply_top(topo_multiplier[0], verbose=verbose) - retTop = retTop._add_top(top = top2.multiply_top(topo_multiplier[1], verbose=verbose), solvFrom1=solvFrom1, verbose=verbose) + retTop = retTop._add_top( + top=top2.multiply_top(topo_multiplier[1], verbose=verbose), solvFrom1=solvFrom1, verbose=verbose + ) else: retTop = top2.multiply_top(topo_multiplier[1], verbose=verbose) - retTop = retTop._add_top(top = top1.multiply_top(topo_multiplier[0], verbose=verbose), solvFrom1=solvFrom1, verbose=verbose) + retTop = retTop._add_top( + top=top1.multiply_top(topo_multiplier[0], verbose=verbose), solvFrom1=solvFrom1, verbose=verbose + ) return retTop - - diff --git a/pygromos/gromos/pyGromosPP/ran_box.py b/pygromos/gromos/pyGromosPP/ran_box.py index db4322e9..0e3f9c31 100644 --- a/pygromos/gromos/pyGromosPP/ran_box.py +++ b/pygromos/gromos/pyGromosPP/ran_box.py @@ -14,52 +14,54 @@ from pygromos.files.topology.top import Top from pygromos.files.coord.cnf import Cnf -def ran_box(in_top_path:str, - in_cnf_path:str, - out_cnf_path:str= "", - periodic_boundary_condition: str = "r", - nmolecule:int = 1, - dens:float = 1.0, - threshold:float=None, - layer:bool = False, - boxsize:float=None, - fixfirst:bool = False, - seed:float=None, - _binary_name="ran_box", - verbose=True, - return_command_only=False)->str: + +def ran_box( + in_top_path: str, + in_cnf_path: str, + out_cnf_path: str = "", + periodic_boundary_condition: str = "r", + nmolecule: int = 1, + dens: float = 1.0, + threshold: float = None, + layer: bool = False, + boxsize: float = None, + fixfirst: bool = False, + seed: float = None, + _binary_name="ran_box", + verbose=True, + return_command_only=False, +) -> str: top = Top(in_value=in_top_path) cnf = Cnf(in_value=in_cnf_path) cog = np.array(cnf.center_of_geometry()) - if(sum([len(cnf.residues[x]) for x in cnf.residues])>1): - raise Exception("ran_box works only with one residue in the .cnf file!\nFound: "+str(cnf.get_residues())) + if sum([len(cnf.residues[x]) for x in cnf.residues]) > 1: + raise Exception("ran_box works only with one residue in the .cnf file!\nFound: " + str(cnf.get_residues())) - #get volume and box length - minwall = 0.12 #saftey distance of a bond length to box edge + # get volume and box length + minwall = 0.12 # saftey distance of a bond length to box edge mol_mass = top.get_mass() volume = 1.66056 * nmolecule * mol_mass / dens - box_length = volume**(1./3.) - divider = int(np.ceil(nmolecule**(1./3.))) - distance = (box_length-2*minwall)/float(divider) + box_length = volume ** (1.0 / 3.0) + divider = int(np.ceil(nmolecule ** (1.0 / 3.0))) + distance = (box_length - 2 * minwall) / float(divider) - #calculate maxRandShift - scale = 0.5 #scale can be manually decreased + # calculate maxRandShift + scale = 0.5 # scale can be manually decreased maxDist = 0 for atom in copy.deepcopy(cnf).POSITION.content: pos = np.array([atom.xp, atom.yp, atom.zp]) - dis = np.linalg.norm(pos-cog) + dis = np.linalg.norm(pos - cog) if dis > maxDist: maxDist = dis - maxRandShift = (scale * distance) -maxDist + maxRandShift = (scale * distance) - maxDist if maxRandShift < 0: maxRandShift = 0 if verbose: warnings.warn("Molecules might overlap! Check cnf manually or decrease the density") - - #create new cnf for return and set some attributes + # create new cnf for return and set some attributes ret_cnf = copy.deepcopy(cnf) ret_cnf.POSITION.content = [] if hasattr(ret_cnf, "LATTICESHIFTS"): @@ -70,23 +72,31 @@ def ran_box(in_top_path:str, delattr(ret_cnf, "STOCHINT") ret_cnf.GENBOX.pbc = 1 ret_cnf.GENBOX.length = [box_length, box_length, box_length] - ret_cnf.GENBOX.angles = [90,90,90] + ret_cnf.GENBOX.angles = [90, 90, 90] ret_cnf.TITLE.content = str(nmolecule) + " * " + cnf.POSITION.content[0].resName # add positions points = list(it.product(range(divider), range(divider), range(divider))) for ind, (xi, yi, zi) in enumerate(random.sample(points, nmolecule)): - shift = np.array([(xi+0.5)*distance+minwall, (yi+0.5)*distance+minwall, (zi+0.5)*distance+minwall]) - cnf.rotate(alpha=random.uniform(0,360), beta=random.uniform(0,360), gamma=random.uniform(0,360)) - randomShift = np.array([random.uniform(-maxRandShift,maxRandShift),random.uniform(-maxRandShift,maxRandShift),random.uniform(-maxRandShift,maxRandShift)]) + shift = np.array( + [(xi + 0.5) * distance + minwall, (yi + 0.5) * distance + minwall, (zi + 0.5) * distance + minwall] + ) + cnf.rotate(alpha=random.uniform(0, 360), beta=random.uniform(0, 360), gamma=random.uniform(0, 360)) + randomShift = np.array( + [ + random.uniform(-maxRandShift, maxRandShift), + random.uniform(-maxRandShift, maxRandShift), + random.uniform(-maxRandShift, maxRandShift), + ] + ) for atom in copy.deepcopy(cnf).POSITION.content: pos = np.array([atom.xp, atom.yp, atom.zp]) atom.xp, atom.yp, atom.zp = pos - cog + shift + randomShift - atom.resID = ind+1 - atom.atomID += (ind * cnf.POSITION.content[-1].atomID) + atom.resID = ind + 1 + atom.atomID += ind * cnf.POSITION.content[-1].atomID ret_cnf.POSITION.content.append(atom) - + ret_cnf.write(out_path=out_cnf_path) return out_cnf_path diff --git a/pygromos/gromos/utils.py b/pygromos/gromos/utils.py index 30ea9724..41474ea1 100644 --- a/pygromos/gromos/utils.py +++ b/pygromos/gromos/utils.py @@ -7,6 +7,7 @@ Decorator """ + def gromosTypeConverter(func): """ This decorator can be used to automatically convert @@ -18,23 +19,31 @@ def gromosTypeConverter(func): ------- """ + @functools.wraps(func) def convert_pyGromos_types(*args, **kwargs): - #no key-word parameters + # no key-word parameters nargs = [] for v in args: - if (isinstance(v, _general_gromos_file._general_gromos_file)): - if(v.path is None or not os.path.exists(v.path)): - raise IOError("please write out the "+str(v.__name__)+" first to use the function "+str(func.__name__)+"") + if isinstance(v, _general_gromos_file._general_gromos_file): + if v.path is None or not os.path.exists(v.path): + raise IOError( + "please write out the " + + str(v.__name__) + + " first to use the function " + + str(func.__name__) + + "" + ) v = v.path nargs.append(v) - #key-value - parameters + # key-value - parameters for k, v in kwargs.items(): - if (isinstance(v, _general_gromos_file._general_gromos_file)): - if(v.path is None or not os.path.exists(v.path)): - raise IOError("please write out the "+k+" first to use the function "+str(func.__name__)+"") + if isinstance(v, _general_gromos_file._general_gromos_file): + if v.path is None or not os.path.exists(v.path): + raise IOError("please write out the " + k + " first to use the function " + str(func.__name__) + "") kwargs[k] = v.path return func(*nargs, **kwargs) - return convert_pyGromos_types \ No newline at end of file + + return convert_pyGromos_types diff --git a/pygromos/pygromos.py b/pygromos/pygromos.py index 96124e3e..caaa241d 100644 --- a/pygromos/pygromos.py +++ b/pygromos/pygromos.py @@ -5,4 +5,5 @@ Handles the primary functions """ import os -package_path = os.path.abspath(os.path.dirname(__file__)+"..") \ No newline at end of file + +package_path = os.path.abspath(os.path.dirname(__file__) + "..") diff --git a/pygromos/simulations/__init__.py b/pygromos/simulations/__init__.py index 44bc2a85..1cf13d5c 100644 --- a/pygromos/simulations/__init__.py +++ b/pygromos/simulations/__init__.py @@ -1,9 +1,9 @@ -#for nice module access +# for nice module access -#from pygromos.simulations.modules.general_simulation_modules import simulation -#from pygromos.simulations.modules.preset_simulation_modules import emin, md, sd -#from pygromos.simulations.modules.ti_modules import TI_sampling +# from pygromos.simulations.modules.general_simulation_modules import simulation +# from pygromos.simulations.modules.preset_simulation_modules import emin, md, sd +# from pygromos.simulations.modules.ti_modules import TI_sampling -#from pygromos.simulations.approaches.hvap_calculation.hvap_calculation import Hvap_calculation +# from pygromos.simulations.approaches.hvap_calculation.hvap_calculation import Hvap_calculation -#from pygromos.simulations.hpc_queuing import submission_systems \ No newline at end of file +# from pygromos.simulations.hpc_queuing import submission_systems diff --git a/pygromos/simulations/approaches/hvap_calculation/hvap_calculation.py b/pygromos/simulations/approaches/hvap_calculation/hvap_calculation.py index f26bb509..caeb9491 100644 --- a/pygromos/simulations/approaches/hvap_calculation/hvap_calculation.py +++ b/pygromos/simulations/approaches/hvap_calculation/hvap_calculation.py @@ -38,8 +38,19 @@ from pygromos.files.topology.top import Top from pygromos.utils.utils import time_wait_s_for_filesystem -class Hvap_calculation(): - def __init__(self, input_system:Gromos_System or str or Chem.rdchem.Mol, work_folder:str, system_name:str="dummy", forcefield:forcefield_system=forcefield_system(name="54A7"), gromosXX:str=None, gromosPP:str=None, useGromosPlsPls:bool=True, verbose:bool=True) -> None: + +class Hvap_calculation: + def __init__( + self, + input_system: Gromos_System or str or Chem.rdchem.Mol, + work_folder: str, + system_name: str = "dummy", + forcefield: forcefield_system = forcefield_system(name="54A7"), + gromosXX: str = None, + gromosPP: str = None, + useGromosPlsPls: bool = True, + verbose: bool = True, + ) -> None: """For a given gromos_system (or smiles) the heat of vaporization is automaticaly calculated Parameters @@ -51,8 +62,14 @@ def __init__(self, input_system:Gromos_System or str or Chem.rdchem.Mol, work_fo if type(input_system) is Gromos_System: self.groSys_gas = input_system elif (type(input_system) is str) or (type(input_system) is Chem.rdchem.Mol): - self.groSys_gas = Gromos_System(work_folder=work_folder, system_name=system_name, in_smiles=input_system, Forcefield=forcefield, in_imd_path=hvap_input_files.imd_hvap_gas_sd, verbose=verbose) - + self.groSys_gas = Gromos_System( + work_folder=work_folder, + system_name=system_name, + in_smiles=input_system, + Forcefield=forcefield, + in_imd_path=hvap_input_files.imd_hvap_gas_sd, + verbose=verbose, + ) self.work_folder = work_folder self.system_name = system_name @@ -65,10 +82,10 @@ def __init__(self, input_system:Gromos_System or str or Chem.rdchem.Mol, work_fo warnings.warn("Folder does already exist") else: pass - self.groSys_gas.work_folder = work_folder + "/" + system_name +"_gas" + self.groSys_gas.work_folder = work_folder + "/" + system_name + "_gas" self.groSys_gas.rebase_files() self.groSys_liq = deepcopy(self.groSys_gas) - self.groSys_liq.work_folder = work_folder + "/" + system_name +"_liq" + self.groSys_liq.work_folder = work_folder + "/" + system_name + "_liq" self.groSys_liq.rebase_files() self.submissonSystem = subSys() @@ -76,7 +93,7 @@ def __init__(self, input_system:Gromos_System or str or Chem.rdchem.Mol, work_fo self.gromosXX = self.groSys_gas.gromosXX self.gromosPP = self.groSys_gas.gromosPP - # define template imd files (overwritte for specific systems) + # define template imd files (overwritte for specific systems) # made for small molecule Hvap calculation self.imd_gas_min = Imd(hvap_input_files.imd_hvap_emin) self.imd_gas_eq = Imd(hvap_input_files.imd_hvap_gas_sd) @@ -109,95 +126,135 @@ def create_liq(self): # create liq top if self.useGromosPlsPls: try: - self.gromosPP.com_top(self.groSys_gas.top.path, topo_multiplier=self.num_molecules, out_top_path=self.work_folder + "/temp.top") - tempTop = Top(in_value=self.work_folder+"/temp.top") - tempTop.write(out_path=self.work_folder+"temp.top") - time.sleep(time_wait_s_for_filesystem) #wait for file to write and close + self.gromosPP.com_top( + self.groSys_gas.top.path, + topo_multiplier=self.num_molecules, + out_top_path=self.work_folder + "/temp.top", + ) + tempTop = Top(in_value=self.work_folder + "/temp.top") + tempTop.write(out_path=self.work_folder + "temp.top") + time.sleep(time_wait_s_for_filesystem) # wait for file to write and close self.groSys_liq.top = tempTop except: - self.groSys_liq.top = com_top(top1=self.groSys_gas.top, top2=self.groSys_gas.top, topo_multiplier=[self.num_molecules,0], verbose=False) + self.groSys_liq.top = com_top( + top1=self.groSys_gas.top, + top2=self.groSys_gas.top, + topo_multiplier=[self.num_molecules, 0], + verbose=False, + ) else: - self.groSys_liq.top = com_top(top1=self.groSys_gas.top, top2=self.groSys_gas.top, topo_multiplier=[self.num_molecules,0], verbose=False) - - - #create liq cnf + self.groSys_liq.top = com_top( + top1=self.groSys_gas.top, + top2=self.groSys_gas.top, + topo_multiplier=[self.num_molecules, 0], + verbose=False, + ) + + # create liq cnf if self.useGromosPlsPls: - self.gromosPP.ran_box(in_top_path=self.groSys_gas.top.path, in_cnf_path=self.groSys_gas.cnf.path, out_cnf_path=self.work_folder+"/temp.cnf", nmolecule=self.num_molecules, dens=self.density, threshold=0.1, layer=True) + self.gromosPP.ran_box( + in_top_path=self.groSys_gas.top.path, + in_cnf_path=self.groSys_gas.cnf.path, + out_cnf_path=self.work_folder + "/temp.cnf", + nmolecule=self.num_molecules, + dens=self.density, + threshold=0.1, + layer=True, + ) else: - ran_box(in_top_path=self.groSys_gas.top.path, in_cnf_path=self.groSys_gas.cnf.path, out_cnf_path=self.work_folder+"/temp.cnf", nmolecule=self.num_molecules, dens=self.density) - time.sleep(time_wait_s_for_filesystem) #wait for file to write and close - self.groSys_liq.cnf = Cnf(in_value=self.work_folder+"/temp.cnf") - - #reset liq system + ran_box( + in_top_path=self.groSys_gas.top.path, + in_cnf_path=self.groSys_gas.cnf.path, + out_cnf_path=self.work_folder + "/temp.cnf", + nmolecule=self.num_molecules, + dens=self.density, + ) + time.sleep(time_wait_s_for_filesystem) # wait for file to write and close + self.groSys_liq.cnf = Cnf(in_value=self.work_folder + "/temp.cnf") + + # reset liq system self.groSys_liq.rebase_files() def run_gas(self): self.groSys_gas.rebase_files() - #min + # min print(self.groSys_gas.work_folder) - sys_emin_gas, jobID = simulation(in_gromos_simulation_system=self.groSys_gas, - override_project_dir=self.groSys_gas.work_folder, - step_name="1_emin", - in_imd_path=self.imd_gas_min, - submission_system=self.submissonSystem, - analysis_script=simulation_analysis.do, - verbose=self.verbose) + sys_emin_gas, jobID = simulation( + in_gromos_simulation_system=self.groSys_gas, + override_project_dir=self.groSys_gas.work_folder, + step_name="1_emin", + in_imd_path=self.imd_gas_min, + submission_system=self.submissonSystem, + analysis_script=simulation_analysis.do, + verbose=self.verbose, + ) print(self.groSys_gas.work_folder) - #eq - sys_eq_gas, jobID = simulation(in_gromos_simulation_system=sys_emin_gas, - override_project_dir=self.groSys_gas.work_folder, - step_name="2_eq", - in_imd_path=self.imd_gas_eq, - submission_system=self.submissonSystem, - analysis_script=simulation_analysis.do, - verbose=self.verbose) - - #sd - sys_sd_gas, jobID = simulation(in_gromos_simulation_system=sys_eq_gas, - override_project_dir=self.groSys_gas.work_folder, - step_name="3_sd", - in_imd_path=self.imd_gas_sd, - submission_system=self.submissonSystem, - analysis_script=simulation_analysis.do, - verbose=self.verbose) + # eq + sys_eq_gas, jobID = simulation( + in_gromos_simulation_system=sys_emin_gas, + override_project_dir=self.groSys_gas.work_folder, + step_name="2_eq", + in_imd_path=self.imd_gas_eq, + submission_system=self.submissonSystem, + analysis_script=simulation_analysis.do, + verbose=self.verbose, + ) + + # sd + sys_sd_gas, jobID = simulation( + in_gromos_simulation_system=sys_eq_gas, + override_project_dir=self.groSys_gas.work_folder, + step_name="3_sd", + in_imd_path=self.imd_gas_sd, + submission_system=self.submissonSystem, + analysis_script=simulation_analysis.do, + verbose=self.verbose, + ) self.groSys_gas_final = sys_sd_gas - def run_liq(self): self.groSys_liq.rebase_files() - #minsys_emin_liq, jobID - sys_emin_liq, jobID = simulation(in_gromos_simulation_system=self.groSys_liq, - override_project_dir=self.groSys_liq.work_folder, - step_name="1_emin", - in_imd_path=self.imd_liq_min, - submission_system=self.submissonSystem, - analysis_script=simulation_analysis.do, - verbose=self.verbose) - - #eq - sys_eq_liq, jobID = simulation(in_gromos_simulation_system=sys_emin_liq, - override_project_dir=self.groSys_liq.work_folder, - step_name="2_eq", - in_imd_path=self.imd_liq_eq, - submission_system=self.submissonSystem, - analysis_script=simulation_analysis.do, - verbose=self.verbose) - - #md - sys_md_liq, jobID = simulation(in_gromos_simulation_system=sys_eq_liq, - override_project_dir=self.groSys_liq.work_folder, - step_name="3_sd", - in_imd_path=self.imd_liq_md, - submission_system=self.submissonSystem, - analysis_script=simulation_analysis.do, - verbose=self.verbose) + # minsys_emin_liq, jobID + sys_emin_liq, jobID = simulation( + in_gromos_simulation_system=self.groSys_liq, + override_project_dir=self.groSys_liq.work_folder, + step_name="1_emin", + in_imd_path=self.imd_liq_min, + submission_system=self.submissonSystem, + analysis_script=simulation_analysis.do, + verbose=self.verbose, + ) + + # eq + sys_eq_liq, jobID = simulation( + in_gromos_simulation_system=sys_emin_liq, + override_project_dir=self.groSys_liq.work_folder, + step_name="2_eq", + in_imd_path=self.imd_liq_eq, + submission_system=self.submissonSystem, + analysis_script=simulation_analysis.do, + verbose=self.verbose, + ) + + # md + sys_md_liq, jobID = simulation( + in_gromos_simulation_system=sys_eq_liq, + override_project_dir=self.groSys_liq.work_folder, + step_name="3_sd", + in_imd_path=self.imd_liq_md, + submission_system=self.submissonSystem, + analysis_script=simulation_analysis.do, + verbose=self.verbose, + ) self.groSys_liq_final = sys_md_liq def calc_hvap(self) -> float: - h_vap = self.groSys_liq_final.tre.get_Hvap(gas_traj=self.groSys_gas_final.tre, nMolecules=self.num_molecules, temperature=self.temperature) + h_vap = self.groSys_liq_final.tre.get_Hvap( + gas_traj=self.groSys_gas_final.tre, nMolecules=self.num_molecules, temperature=self.temperature + ) return h_vap diff --git a/pygromos/simulations/approaches/hvap_calculation/hvap_input_files/__init__.py b/pygromos/simulations/approaches/hvap_calculation/hvap_input_files/__init__.py index d64b1ff0..7dd5852e 100644 --- a/pygromos/simulations/approaches/hvap_calculation/hvap_input_files/__init__.py +++ b/pygromos/simulations/approaches/hvap_calculation/hvap_input_files/__init__.py @@ -3,8 +3,7 @@ import os dir_path = os.path.dirname(__file__) -imd_hvap_emin = dir_path +"/emin.imd" -imd_hvap_gas_sd = dir_path +"/gas_sd.imd" -imd_hvap_liquid_eq = dir_path +"/liquid_eq.imd" -imd_hvap_liquid_md = dir_path +"/liquid_md.imd" - +imd_hvap_emin = dir_path + "/emin.imd" +imd_hvap_gas_sd = dir_path + "/gas_sd.imd" +imd_hvap_liquid_eq = dir_path + "/liquid_eq.imd" +imd_hvap_liquid_md = dir_path + "/liquid_md.imd" diff --git a/pygromos/simulations/approaches/hvap_calculation/hvap_input_files/emin.imd b/pygromos/simulations/approaches/hvap_calculation/hvap_input_files/emin.imd index e080528a..381b568d 100644 --- a/pygromos/simulations/approaches/hvap_calculation/hvap_input_files/emin.imd +++ b/pygromos/simulations/approaches/hvap_calculation/hvap_input_files/emin.imd @@ -49,7 +49,7 @@ FORCE # bonds angles improper dihedral electrostatic vdW 0 1 1 1 1 1 # NEGR NRE(1) NRE(2) ... NRE(NEGR) - 1 18 + 1 18 END # with rectangular periodic boundary conditions we may use # the grid based pairlist generation @@ -79,4 +79,3 @@ WRITETRAJ # NTWX NTWSE NTWV NTWF NTWE NTWG NTWB 100 0 0 0 100 0 0 END - diff --git a/pygromos/simulations/approaches/hvap_calculation/hvap_input_files/liquid_eq.imd b/pygromos/simulations/approaches/hvap_calculation/hvap_input_files/liquid_eq.imd index 407c8e3b..55d316c4 100644 --- a/pygromos/simulations/approaches/hvap_calculation/hvap_input_files/liquid_eq.imd +++ b/pygromos/simulations/approaches/hvap_calculation/hvap_input_files/liquid_eq.imd @@ -105,7 +105,7 @@ END # Default : 1.2 # AMBER AMBSCAL # 1 1.2 -#END +#END PRINTOUT #NTPR: print out energies, etc. every NTPR steps #NTPP: =1 perform dihedral angle transition monitoring diff --git a/pygromos/simulations/approaches/hvap_calculation/hvap_input_files/liquid_md.imd b/pygromos/simulations/approaches/hvap_calculation/hvap_input_files/liquid_md.imd index f60e7967..45d37a73 100644 --- a/pygromos/simulations/approaches/hvap_calculation/hvap_input_files/liquid_md.imd +++ b/pygromos/simulations/approaches/hvap_calculation/hvap_input_files/liquid_md.imd @@ -105,7 +105,7 @@ END # Default : 1.2 # AMBER AMBSCAL # 1 1.2 -#END +#END PRINTOUT #NTPR: print out energies, etc. every NTPR steps #NTPP: =1 perform dihedral angle transition monitoring diff --git a/pygromos/simulations/approaches/solvation_free_energy_calculation/solvation_free_energy.py b/pygromos/simulations/approaches/solvation_free_energy_calculation/solvation_free_energy.py index e8a1b977..09255361 100644 --- a/pygromos/simulations/approaches/solvation_free_energy_calculation/solvation_free_energy.py +++ b/pygromos/simulations/approaches/solvation_free_energy_calculation/solvation_free_energy.py @@ -43,8 +43,13 @@ from pygromos.simulations.modules.general_simulation_modules import simulation from pygromos.simulations.hpc_queuing.job_scheduling.workers.analysis_workers import simulation_analysis from pygromos.files.topology.ptp import Pertubation_topology -from pygromos.files.blocks.topology_blocks import pertubation_lam_state, atom_lam_pertubation_state, PERTATOMPARAM, \ - TITLE, SCALEDINTERACTIONS +from pygromos.files.blocks.topology_blocks import ( + pertubation_lam_state, + atom_lam_pertubation_state, + PERTATOMPARAM, + TITLE, + SCALEDINTERACTIONS, +) from pygromos.files.blocks.imd_blocks import PRESSURESCALE, PERTURBATION, MULTIBATH from pygromos.files.blocks.imd_blocks import RANDOMNUMBERS from pygromos.analysis.error_estimate import error_estimator @@ -53,8 +58,9 @@ import pandas as pd from pygromos.files.trajectory.trg import Trg + class Solvation_free_energy_calculation: - ''' + """ A class used to calculate Solvation Free Energies ... @@ -90,12 +96,27 @@ class Solvation_free_energy_calculation: Number of OMP cores to use amberscaling : bool whether to use amberscaling (not implemented on all GROMOS Branches) - ''' - def __init__(self, input_system: Gromos_System or str or Chem.rdchem.Mol, work_folder: str, - system_name: str = "dummy", forcefield: forcefield_system = forcefield_system(name="54A7"), - gromosXX: str = None, gromosPP: str = None, useGromosPlsPls: bool = True, - verbose: bool = True, num_molecules: int = 512, density: float = 1000, num_atoms: int = 0, - subsystem: str = "lsf",nmpi = 6, nomp = 1, provided_topo : str = None, amberscaling = False) -> None: + """ + + def __init__( + self, + input_system: Gromos_System or str or Chem.rdchem.Mol, + work_folder: str, + system_name: str = "dummy", + forcefield: forcefield_system = forcefield_system(name="54A7"), + gromosXX: str = None, + gromosPP: str = None, + useGromosPlsPls: bool = True, + verbose: bool = True, + num_molecules: int = 512, + density: float = 1000, + num_atoms: int = 0, + subsystem: str = "lsf", + nmpi=6, + nomp=1, + provided_topo: str = None, + amberscaling=False, + ) -> None: self.verbose = verbose self.amberscaling = amberscaling @@ -104,8 +125,14 @@ def __init__(self, input_system: Gromos_System or str or Chem.rdchem.Mol, work_f if type(input_system) is Gromos_System: self.groSys_liq = input_system elif (type(input_system) is str) or (type(input_system) is Chem.rdchem.Mol): - self.groSys_liq = Gromos_System(system_name="ff2_" + input_system, work_folder=work_folder, - in_smiles=input_system, auto_convert=True, Forcefield=forcefield,adapt_imd_automatically=False) + self.groSys_liq = Gromos_System( + system_name="ff2_" + input_system, + work_folder=work_folder, + in_smiles=input_system, + auto_convert=True, + Forcefield=forcefield, + adapt_imd_automatically=False, + ) if provided_topo: self.groSys_liq.top = Top(provided_topo) @@ -119,11 +146,10 @@ def __init__(self, input_system: Gromos_System or str or Chem.rdchem.Mol, work_f top = openforcefield2gromos(molecule).convert_return() # Setter not working, manual check needed - assert isinstance(top,Top) + assert isinstance(top, Top) self.groSys_liq._top = top self.groSys_liq.rebase_files() - self.work_folder = work_folder self.system_name = system_name @@ -136,7 +162,6 @@ def __init__(self, input_system: Gromos_System or str or Chem.rdchem.Mol, work_f else: pass - self.groSys_liq.work_folder = work_folder + "/" + system_name + "_liq" self.groSys_liq.rebase_files() @@ -145,10 +170,9 @@ def __init__(self, input_system: Gromos_System or str or Chem.rdchem.Mol, work_f self._nomp = nomp self._subsystem = subsystem - #Create System + # Create System self.create_new_submission_system() - self.gromosXX = self.groSys_liq.gromosXX self.gromosPP = self.groSys_liq.gromosPP @@ -168,9 +192,8 @@ def __init__(self, input_system: Gromos_System or str or Chem.rdchem.Mol, work_f self.useGromosPlsPls = useGromosPlsPls - def run(self): - ''' + """ Run five step Process to calculate Self Solvation Free Energies 1) Create Topology and Box with Molecules 2) Energy minimize the system @@ -181,17 +204,17 @@ def run(self): Returns ------- - ''' + """ self.create_liq() emin_sys, jobID = self.minimize_liq(in_gromos_simulation_system=self.groSys_liq, prev_JobID=-1) eq_sys, jobID = self.eq_liq(in_gromos_simulation_system=emin_sys, prev_JobID=jobID) ti_sys, jobID = self.ti_liq(in_gromos_simulation_system=eq_sys, prev_JobID=jobID) - self.calculate_solvation_free_energy(ti_sys,jobID) + self.calculate_solvation_free_energy(ti_sys, jobID) def create_liq(self): - ''' + """ Create Coordinates and Topology for Liquid System - ''' + """ # Test for fast add up if not np.log2(self.num_molecules) % 1: @@ -204,7 +227,6 @@ def create_liq(self): new_top += self.groSys_liq.top self.groSys_liq.top = new_top - # Create location for coordinates coord_dir = self.work_folder + "/coord/" try: @@ -218,11 +240,13 @@ def create_liq(self): out_cnf_path = coord_dir + self.system_name + str(self.num_molecules) + ".cnf" # Create Box - box_cnf_path = ran_box(in_top_path=self.groSys_liq.top.path, - in_cnf_path=self.groSys_liq.cnf.path, - out_cnf_path=out_cnf_path, - nmolecule=self.num_molecules, - dens=self.density) + box_cnf_path = ran_box( + in_top_path=self.groSys_liq.top.path, + in_cnf_path=self.groSys_liq.cnf.path, + out_cnf_path=out_cnf_path, + nmolecule=self.num_molecules, + dens=self.density, + ) self.groSys_liq.cnf = Cnf(in_value=box_cnf_path) @@ -230,7 +254,7 @@ def create_liq(self): self.groSys_liq.rebase_files() def minimize_liq(self, in_gromos_simulation_system: Gromos_System, prev_JobID: int): - ''' + """ Minimize Liquide Parameters ---------- @@ -244,21 +268,32 @@ def minimize_liq(self, in_gromos_simulation_system: Gromos_System, prev_JobID: i Energy minimized Gromos System jobID : int ID of submitted job for the next job to wait for (only relevant for LSF) - ''' + """ in_gromos_simulation_system.adapt_imd_automatically = False in_gromos_simulation_system.imd = self.imd_liq_min - emin_sys = simulation(in_gromos_simulation_system=in_gromos_simulation_system, override_project_dir=self.groSys_liq.work_folder, - step_name=self.system_name + "_emin", - submission_system=self.submissonSystem, - analysis_script=simulation_analysis.do, - verbose=self.verbose) + emin_sys = simulation( + in_gromos_simulation_system=in_gromos_simulation_system, + override_project_dir=self.groSys_liq.work_folder, + step_name=self.system_name + "_emin", + submission_system=self.submissonSystem, + analysis_script=simulation_analysis.do, + verbose=self.verbose, + ) return emin_sys, emin_sys._last_jobID - def equilibration_gromos_system_step(self, in_gromos_simulation_system: Gromos_System, NTIVAL: int = 0, NTISHI: int = 0, - TEMPI: float = 0, TEMPO: float = 0, prevID: int = -1, run_name: str = "", - natoms: int = 0): - ''' + def equilibration_gromos_system_step( + self, + in_gromos_simulation_system: Gromos_System, + NTIVAL: int = 0, + NTISHI: int = 0, + TEMPI: float = 0, + TEMPO: float = 0, + prevID: int = -1, + run_name: str = "", + natoms: int = 0, + ): + """ Perform one step in equilibration routine Parameters ---------- @@ -285,15 +320,16 @@ def equilibration_gromos_system_step(self, in_gromos_simulation_system: Gromos_S Equilibrated gromos system JobID : int ID of the submitted job for the next job to wait on - ''' + """ # adapt imd eq_imd = Imd(template_md) eq_imd.SYSTEM.NSM = 0 eq_imd.STEP.NSTLIM = 25000 - multibath = MULTIBATH(ALGORITHM=0, NBATHS=1, TEMP0=[TEMPO], TAU=[0.1], DOFSET=1, - LAST=[natoms], COMBATH=[1], IRBATH=[1]) + multibath = MULTIBATH( + ALGORITHM=0, NBATHS=1, TEMP0=[TEMPO], TAU=[0.1], DOFSET=1, LAST=[natoms], COMBATH=[1], IRBATH=[1] + ) eq_imd.MULTIBATH = multibath eq_imd.PRESSURESCALE.COUPLE = 1 @@ -326,22 +362,31 @@ def equilibration_gromos_system_step(self, in_gromos_simulation_system: Gromos_S eq_imd.randomize_seed() if prevID == -1: - md_sys = simulation(in_gromos_simulation_system=in_gromos_simulation_system, override_project_dir=self.groSys_liq.work_folder, - step_name="eq" + run_name, in_imd_path=eq_imd, - submission_system=self.submissonSystem, - analysis_script=simulation_analysis.do, - verbose=self.verbose) + md_sys = simulation( + in_gromos_simulation_system=in_gromos_simulation_system, + override_project_dir=self.groSys_liq.work_folder, + step_name="eq" + run_name, + in_imd_path=eq_imd, + submission_system=self.submissonSystem, + analysis_script=simulation_analysis.do, + verbose=self.verbose, + ) else: - md_sys = simulation(in_gromos_simulation_system=in_gromos_simulation_system, override_project_dir=self.groSys_liq.work_folder, - step_name="eq" + run_name, in_imd_path=eq_imd, - submission_system=self.submissonSystem, - analysis_script=simulation_analysis.do, - verbose=self.verbose, previous_simulation_run=prevID) + md_sys = simulation( + in_gromos_simulation_system=in_gromos_simulation_system, + override_project_dir=self.groSys_liq.work_folder, + step_name="eq" + run_name, + in_imd_path=eq_imd, + submission_system=self.submissonSystem, + analysis_script=simulation_analysis.do, + verbose=self.verbose, + previous_simulation_run=prevID, + ) return md_sys, md_sys._last_jobID def eq_liq(self, in_gromos_simulation_system: Gromos_System, prev_JobID: int): - ''' + """ Function to equilibrate the liquid following a 5 step scheme by sequentially calling self.equilibration_gromos_system_step() with different paramteres Parameters @@ -354,36 +399,66 @@ def eq_liq(self, in_gromos_simulation_system: Gromos_System, prev_JobID: int): Returns ------- - ''' + """ # Start equilibration in_gromos_simulation_system.imd = Imd(template_md) # Equilibrate system and pass on for next step - eq_sys1, JobID1 = self.equilibration_gromos_system_step(in_gromos_simulation_system=in_gromos_simulation_system, NTIVAL=1, NTISHI=1, TEMPI=60, - TEMPO=60, - prevID=prev_JobID, run_name=self.system_name + "_eq_1", - natoms=self.num_atoms * self.num_molecules) - eq_sys2, JobID2 = self.equilibration_gromos_system_step(in_gromos_simulation_system=eq_sys1, NTIVAL=0, NTISHI=0, TEMPI=0, - TEMPO=120, - prevID=JobID1, run_name=self.system_name + "_eq_2", - natoms=self.num_atoms * self.num_molecules) - eq_sys3, JobID3 = self.equilibration_gromos_system_step(in_gromos_simulation_system=eq_sys2, NTIVAL=0, NTISHI=0, TEMPI=0, - TEMPO=180, - prevID=JobID2, run_name=self.system_name + "_eq_3", - natoms=self.num_atoms * self.num_molecules) - eq_sys4, JobID4 = self.equilibration_gromos_system_step(in_gromos_simulation_system=eq_sys3, NTIVAL=0, NTISHI=0, TEMPI=0, - TEMPO=240, - prevID=JobID3, run_name=self.system_name + "_eq_4", - natoms=self.num_atoms * self.num_molecules) - eq_sys5, JobID5 = self.equilibration_gromos_system_step(in_gromos_simulation_system=eq_sys4, NTIVAL=0, NTISHI=0, TEMPI=0, - TEMPO=285, - prevID=JobID4, run_name=self.system_name + "_eq_5", - natoms=self.num_atoms * self.num_molecules) + eq_sys1, JobID1 = self.equilibration_gromos_system_step( + in_gromos_simulation_system=in_gromos_simulation_system, + NTIVAL=1, + NTISHI=1, + TEMPI=60, + TEMPO=60, + prevID=prev_JobID, + run_name=self.system_name + "_eq_1", + natoms=self.num_atoms * self.num_molecules, + ) + eq_sys2, JobID2 = self.equilibration_gromos_system_step( + in_gromos_simulation_system=eq_sys1, + NTIVAL=0, + NTISHI=0, + TEMPI=0, + TEMPO=120, + prevID=JobID1, + run_name=self.system_name + "_eq_2", + natoms=self.num_atoms * self.num_molecules, + ) + eq_sys3, JobID3 = self.equilibration_gromos_system_step( + in_gromos_simulation_system=eq_sys2, + NTIVAL=0, + NTISHI=0, + TEMPI=0, + TEMPO=180, + prevID=JobID2, + run_name=self.system_name + "_eq_3", + natoms=self.num_atoms * self.num_molecules, + ) + eq_sys4, JobID4 = self.equilibration_gromos_system_step( + in_gromos_simulation_system=eq_sys3, + NTIVAL=0, + NTISHI=0, + TEMPI=0, + TEMPO=240, + prevID=JobID3, + run_name=self.system_name + "_eq_4", + natoms=self.num_atoms * self.num_molecules, + ) + eq_sys5, JobID5 = self.equilibration_gromos_system_step( + in_gromos_simulation_system=eq_sys4, + NTIVAL=0, + NTISHI=0, + TEMPI=0, + TEMPO=285, + prevID=JobID4, + run_name=self.system_name + "_eq_5", + natoms=self.num_atoms * self.num_molecules, + ) return eq_sys5, JobID5 - def ti_liq(self, in_gromos_simulation_system: Gromos_System, prev_JobID: int, n_points:int = 21): - ''' + def ti_liq(self, in_gromos_simulation_system: Gromos_System, prev_JobID: int, n_points: int = 21): + """ Perform TI of Liquid Parameters ---------- @@ -398,7 +473,7 @@ def ti_liq(self, in_gromos_simulation_system: Gromos_System, prev_JobID: int, n_ ------- JobID : int ID of last submitted job (WARNING it could be that this job finishes before some others manual check needed) - ''' + """ # First generate ptp file in_gromos_simulation_system = self.add_ptp_file(in_gromos_simulation_system) @@ -429,12 +504,20 @@ def ti_liq(self, in_gromos_simulation_system: Gromos_System, prev_JobID: int, n_ # First run has longer equilibration time and different naming scheme if rlam == 0: system_name = self.system_name + "_L" + str(rlam) + "_" + str(iteration) - c_ti_sys0_prep = self.set_up_ti_lambda_run(in_gromos_simulation_system=in_gromos_simulation_system, NSTLIM=175000, RLAM=rlam, - system_name=system_name) + c_ti_sys0_prep = self.set_up_ti_lambda_run( + in_gromos_simulation_system=in_gromos_simulation_system, + NSTLIM=175000, + RLAM=rlam, + system_name=system_name, + ) c_ti_sys0_prep.adapt_imd_automatically = False - c_ti_sys0 = sd(in_gromos_system=c_ti_sys0_prep, override_project_dir=ti_dir + system_name, - step_name=system_name, submission_system=self.submissonSystem, - previous_simulation_run=prev_JobID) + c_ti_sys0 = sd( + in_gromos_system=c_ti_sys0_prep, + override_project_dir=ti_dir + system_name, + step_name=system_name, + submission_system=self.submissonSystem, + previous_simulation_run=prev_JobID, + ) else: # Set system Name and previous system system_name = self.system_name + "_L" + str(rlam) + "_" + str(iteration) @@ -444,12 +527,19 @@ def ti_liq(self, in_gromos_simulation_system: Gromos_System, prev_JobID: int, n_ previous_system_name = self.system_name + "_L" + str(previous_rlam) + "_0" # Setup second step - c_ti_sys0_prep = self.set_up_ti_lambda_run(in_gromos_simulation_system=systems[previous_system_name], NSTLIM=25000, - RLAM=rlam, - system_name=system_name) - c_ti_sys0 = sd(in_gromos_system=c_ti_sys0_prep, override_project_dir=ti_dir + system_name, - step_name=system_name, submission_system=self.submissonSystem, - previous_simulation_run=jobIDs[previous_system_name]) + c_ti_sys0_prep = self.set_up_ti_lambda_run( + in_gromos_simulation_system=systems[previous_system_name], + NSTLIM=25000, + RLAM=rlam, + system_name=system_name, + ) + c_ti_sys0 = sd( + in_gromos_system=c_ti_sys0_prep, + override_project_dir=ti_dir + system_name, + step_name=system_name, + submission_system=self.submissonSystem, + previous_simulation_run=jobIDs[previous_system_name], + ) JobID = c_ti_sys0._last_jobID @@ -463,12 +553,19 @@ def ti_liq(self, in_gromos_simulation_system: Gromos_System, prev_JobID: int, n_ previous_system_name = self.system_name + "_L" + str(rlam) + "_" + str(iteration - 1) # Setup second step - c_ti_sys1_prep = self.set_up_ti_lambda_run(in_gromos_simulation_system=systems[previous_system_name], NSTLIM=25000, - RLAM=rlam, - system_name=system_name) - c_ti_sys1 = sd(in_gromos_system=c_ti_sys1_prep, override_project_dir=ti_dir + system_name, - step_name=system_name, submission_system=self.submissonSystem, - previous_simulation_run=jobIDs[previous_system_name]) + c_ti_sys1_prep = self.set_up_ti_lambda_run( + in_gromos_simulation_system=systems[previous_system_name], + NSTLIM=25000, + RLAM=rlam, + system_name=system_name, + ) + c_ti_sys1 = sd( + in_gromos_system=c_ti_sys1_prep, + override_project_dir=ti_dir + system_name, + step_name=system_name, + submission_system=self.submissonSystem, + previous_simulation_run=jobIDs[previous_system_name], + ) JobID = c_ti_sys1._last_jobID # Put System into dictionary @@ -479,12 +576,19 @@ def ti_liq(self, in_gromos_simulation_system: Gromos_System, prev_JobID: int, n_ system_name = self.system_name + "_L" + str(rlam) + "_" + str(iteration) previous_system_name = self.system_name + "_L" + str(rlam) + "_" + str(iteration - 1) - c_ti_sys2_prep = self.set_up_ti_lambda_run(in_gromos_simulation_system=systems[previous_system_name], NSTLIM=500000, - RLAM=rlam, - system_name=system_name) - c_ti_sys2 = sd(in_gromos_system=c_ti_sys2_prep, override_project_dir=ti_dir + system_name, - step_name=system_name, submission_system=self.submissonSystem, - previous_simulation_run=jobIDs[previous_system_name]) + c_ti_sys2_prep = self.set_up_ti_lambda_run( + in_gromos_simulation_system=systems[previous_system_name], + NSTLIM=500000, + RLAM=rlam, + system_name=system_name, + ) + c_ti_sys2 = sd( + in_gromos_system=c_ti_sys2_prep, + override_project_dir=ti_dir + system_name, + step_name=system_name, + submission_system=self.submissonSystem, + previous_simulation_run=jobIDs[previous_system_name], + ) JobID = c_ti_sys2._last_jobID @@ -494,9 +598,10 @@ def ti_liq(self, in_gromos_simulation_system: Gromos_System, prev_JobID: int, n_ return JobID, c_ti_sys2 - def set_up_ti_lambda_run(self, in_gromos_simulation_system: Gromos_System, NSTLIM: int = 0, RLAM: float = 0, - system_name: str = ""): - ''' + def set_up_ti_lambda_run( + self, in_gromos_simulation_system: Gromos_System, NSTLIM: int = 0, RLAM: float = 0, system_name: str = "" + ): + """ Setup on TI run by setting the lambda value and steps Parameters ---------- @@ -513,7 +618,7 @@ def set_up_ti_lambda_run(self, in_gromos_simulation_system: Gromos_System, NSTLI ------- gromos_system : Gromos_System Prepared Gromos System - ''' + """ # Do not change imd automatically in_gromos_simulation_system.adapt_imd_automatically = False @@ -535,7 +640,7 @@ def set_up_ti_lambda_run(self, in_gromos_simulation_system: Gromos_System, NSTLI return in_gromos_simulation_system def add_ptp_file(self, in_gromos_simulation_system: Gromos_System): - ''' + """ Function to generate a perturbation Topology Parameters ---------- @@ -546,22 +651,22 @@ def add_ptp_file(self, in_gromos_simulation_system: Gromos_System): ------- gromos_system : Gromos_System Gromos system with added perturbation Topology - ''' + """ # Setup lambda States pert_atoms = [] # Set only atoms of the first molecule - for atom_line in in_gromos_simulation_system.top.SOLUTEATOM[:self.num_atoms]: + for atom_line in in_gromos_simulation_system.top.SOLUTEATOM[: self.num_atoms]: # Get atoms and the correct states states = {} phys_state = pertubation_lam_state(IAC=atom_line.IAC, MASS=atom_line.MASS, CHARGE=atom_line.CG) # Generate a second set of states (a bit hackish) - states = {atom_line.MRES: phys_state, - atom_line.MRES + 1: phys_state} - pert_atom = atom_lam_pertubation_state(atom_line.ATNM, RES=atom_line.MRES, NAME=atom_line.PANM, - STATES=states) + states = {atom_line.MRES: phys_state, atom_line.MRES + 1: phys_state} + pert_atom = atom_lam_pertubation_state( + atom_line.ATNM, RES=atom_line.MRES, NAME=atom_line.PANM, STATES=states + ) pert_atoms.append(pert_atom) # Make Pertubation block @@ -570,7 +675,9 @@ def add_ptp_file(self, in_gromos_simulation_system: Gromos_System): # Generate ptp file in_gromos_simulation_system.ptp = Pertubation_topology(in_value=None) in_gromos_simulation_system.ptp.PERTATOMPARAM = pert_atom_block - in_gromos_simulation_system.ptp.TITLE = TITLE("Automatic generated pertubation file. For Solvation Free Energy calculation") + in_gromos_simulation_system.ptp.TITLE = TITLE( + "Automatic generated pertubation file. For Solvation Free Energy calculation" + ) content_dict = [1, 1, 2, 1, 0] scaled = SCALEDINTERACTIONS(values=content_dict) @@ -615,7 +722,7 @@ def create_liq_min_imd(self): if self.amberscaling: print("Amber Scling is enabled") # Add AMBER Block - amber_block = AMBER(True,1.2) + amber_block = AMBER(True, 1.2) emin_imd.add_block(block=amber_block) # adjust initialize @@ -628,19 +735,19 @@ def create_liq_min_imd(self): return emin_imd def create_liq_eq_imd(self): - ''' + """ Not implemented done on the fly in the eq_liq function - ''' + """ pass def create_liq_ti_imd(self): - ''' + """ Create IMD to perform TI Returns ------- ti_imd : Imd Processed Imd file - ''' + """ # set new template ti_imd = Imd(template_sd) @@ -656,9 +763,15 @@ def create_liq_ti_imd(self): ti_imd.STOCHDYN.TEMPSD = 298.15 # Add Pressurescale - pressurescale = PRESSURESCALE(COUPLE=2, SCALE=1, COMP=0.0004575, - TAUP=0.5, VIRIAL=2, SEMIANISOTROPIC=[1, 1, 1], - PRES0=[[0.6102, 0, 0], [0, 0.6102, 0], [0, 0, 0.6102]]) + pressurescale = PRESSURESCALE( + COUPLE=2, + SCALE=1, + COMP=0.0004575, + TAUP=0.5, + VIRIAL=2, + SEMIANISOTROPIC=[1, 1, 1], + PRES0=[[0.6102, 0, 0], [0, 0.6102, 0], [0, 0, 0.6102]], + ) ti_imd.add_block(block=pressurescale) # Adjust forces @@ -704,7 +817,7 @@ def create_liq_ti_imd(self): if self.amberscaling: # Add AMBER Block - amber_block = AMBER(True,1.2) + amber_block = AMBER(True, 1.2) ti_imd.add_block(block=amber_block) # Adjust Inintialize @@ -713,15 +826,13 @@ def create_liq_ti_imd(self): ti_imd.INITIALISE.NTICOM = 1 ti_imd.INITIALISE.TEMPI = 298.15 - # Add PERTURBATION Block - pert_block = PERTURBATION(NTG=1, NRDGL=0, RLAM=0, DLAMT=0, - ALPHLJ=0.5, ALPHC=0.5, NLAM=1, NSCALE=1) + pert_block = PERTURBATION(NTG=1, NRDGL=0, RLAM=0, DLAMT=0, ALPHLJ=0.5, ALPHC=0.5, NLAM=1, NSCALE=1) ti_imd.add_block(block=pert_block) return ti_imd - def calculate_solvation_free_energy(self,n_points : int = 21): - ''' + def calculate_solvation_free_energy(self, n_points: int = 21): + """ Function to Calculate solvation free energy by integrating over lambda points Parameters ---------- @@ -734,7 +845,7 @@ def calculate_solvation_free_energy(self,n_points : int = 21): Solvation Free Energy error : float Error Estimate - ''' + """ # Get dhdl information Metrics = pd.DataFrame() @@ -768,16 +879,15 @@ def calculate_solvation_free_energy(self,n_points : int = 21): else: sim_tar_exists = False - # get trg info if os.path.isfile(path + "simulation/" + system_name + "_1/" + system_name + "_1.trg.gz"): trg = Trg(path + "simulation/" + system_name + "_1/" + system_name + "_1.trg.gz") elif os.path.isfile(path + "simulation/" + system_name + "_1/" + system_name + "_1.trg"): - warnings.warn('Simulation did not finish correctly using limited data!') + warnings.warn("Simulation did not finish correctly using limited data!") trg = Trg(path + "simulation/" + system_name + "_1/" + system_name + "_1.trg") else: print(path + "simulation/" + system_name + "_1/" + system_name) - exit('No Files have been found') + exit("No Files have been found") dhdls = [trg.database.totals[i][2] for i in range(len(trg.database.totals))] @@ -791,7 +901,6 @@ def calculate_solvation_free_energy(self,n_points : int = 21): rmsds.append(error_estimator(dhdls).calculate_rmsd()) ees.append(error_estimator(dhdls).calculate_error_estimate()) - Metrics["Lambda"] = lambdas Metrics["avg"] = averages Metrics["rmsd"] = rmsds @@ -803,7 +912,7 @@ def calculate_solvation_free_energy(self,n_points : int = 21): if self.verbose: print(Metrics) - print("Solvation Free Energy:",solv_energy,"pm",error) + print("Solvation Free Energy:", solv_energy, "pm", error) return solv_energy, error @@ -818,7 +927,7 @@ def nmpi(self): return self._nmpi @nmpi.setter - def nmpi(self,nmpi=1): + def nmpi(self, nmpi=1): self._nmpi = nmpi self.create_new_submission_system() @@ -838,4 +947,4 @@ def subsystem(self): @subsystem.setter def subsystem(self, subsystem="local"): self._subsystem = subsystem - self.create_new_submission_system() \ No newline at end of file + self.create_new_submission_system() diff --git a/pygromos/simulations/hpc_queuing/job_scheduling/file_management.py b/pygromos/simulations/hpc_queuing/job_scheduling/file_management.py index fd9fcbdd..951afc5f 100644 --- a/pygromos/simulations/hpc_queuing/job_scheduling/file_management.py +++ b/pygromos/simulations/hpc_queuing/job_scheduling/file_management.py @@ -16,9 +16,21 @@ """ PARALLEL WORKER - These functions are required for parallelized code Execution """ -def _thread_worker_cat_trc(job: int, replicaID_range: (Iterable, List[int]), trc_files: Dict[int, List[str]], - out_prefix: str, topology_path: str, out_trcs: dict, dt: float, time: float = 0, - verbose: bool = False, boundary_conditions: str = "r cog", include_all: bool = False): + + +def _thread_worker_cat_trc( + job: int, + replicaID_range: (Iterable, List[int]), + trc_files: Dict[int, List[str]], + out_prefix: str, + topology_path: str, + out_trcs: dict, + dt: float, + time: float = 0, + verbose: bool = False, + boundary_conditions: str = "r cog", + include_all: bool = False, +): """_thread_worker_cat_trc This thread worker_scripts concatenates all .trc files of one replica into one file. @@ -40,79 +52,112 @@ def _thread_worker_cat_trc(job: int, replicaID_range: (Iterable, List[int]), trc gromPP = gromosPP.GromosPP() start_dir = os.getcwd() - if (verbose): print("JOB " + str(job) + ": range " + str(list(replicaID_range))) + if verbose: + print("JOB " + str(job) + ": range " + str(list(replicaID_range))) for replicaID in replicaID_range: out_path = out_prefix + str(replicaID) + ".trc" compress_out_path = out_path + ".gz" out_trcs.update({replicaID: compress_out_path}) - if (os.path.exists(compress_out_path)): # found perfect compressed trc file:) + if os.path.exists(compress_out_path): # found perfect compressed trc file:) warnings.warn("Skipped generating file as I found: " + compress_out_path) - if (os.path.exists(out_path)): + if os.path.exists(out_path): bash.remove_file(out_path) continue - elif (os.path.exists(out_path)): # did not find compressed file. will compress + elif os.path.exists(out_path): # did not find compressed file. will compress warnings.warn("Skipped generating file as I found: " + out_path) continue else: # concat files - if (verbose): print("JOB " + str(job) + ": " + "write out " + out_path + "\n") + if verbose: + print("JOB " + str(job) + ": " + "write out " + out_path + "\n") out_dir = os.path.dirname(out_path) tmp_dir = bash.make_folder(out_dir + "/TMP_replica_" + str(replicaID), additional_option="-p") os.chdir(tmp_dir) - if (include_all): - out_path = gromPP.frameout(in_top_path=topology_path, in_coord_path=" ".join(trc_files[replicaID]), - periodic_boundary_condition=boundary_conditions, single_file=True, - out_file_format="trc", - out_file_path=out_path, time=time, dt=dt, include="ALL") + if include_all: + out_path = gromPP.frameout( + in_top_path=topology_path, + in_coord_path=" ".join(trc_files[replicaID]), + periodic_boundary_condition=boundary_conditions, + single_file=True, + out_file_format="trc", + out_file_path=out_path, + time=time, + dt=dt, + include="ALL", + ) else: - out_path = gromPP.frameout(in_top_path=topology_path, in_coord_path=" ".join(trc_files[replicaID]), - periodic_boundary_condition=boundary_conditions, single_file=True, - out_file_format="trc", - out_file_path=out_path, time=time, dt=dt) + out_path = gromPP.frameout( + in_top_path=topology_path, + in_coord_path=" ".join(trc_files[replicaID]), + periodic_boundary_condition=boundary_conditions, + single_file=True, + out_file_format="trc", + out_file_path=out_path, + time=time, + dt=dt, + ) os.chdir(start_dir) bash.wait_for_fileSystem(out_path) bash.remove_folder(tmp_dir) - if (verbose): print("JOB " + str(job) + ": " + "write out " + out_path + "\t DONE\n") + if verbose: + print("JOB " + str(job) + ": " + "write out " + out_path + "\t DONE\n") - if (verbose): print("JOB " + str(job) + ": " + "compress " + compress_out_path + "\n") + if verbose: + print("JOB " + str(job) + ": " + "compress " + compress_out_path + "\n") compressed_trc = bash.compress_gzip(out_path, out_path=compress_out_path) - if (verbose): print("JOB " + str(job) + ": " + "compress " + compressed_trc + "\t DONE\n") + if verbose: + print("JOB " + str(job) + ": " + "compress " + compressed_trc + "\t DONE\n") -def _thread_worker_cat_tre(job: int, replicaID_range: (Iterable, List[int]), tre_files: Dict[int, List[str]], - out_prefix: str, out_tres: dict, verbose: bool = False): - if (verbose): print("JOB " + str(job) + ": range " + str(list(replicaID_range))) +def _thread_worker_cat_tre( + job: int, + replicaID_range: (Iterable, List[int]), + tre_files: Dict[int, List[str]], + out_prefix: str, + out_tres: dict, + verbose: bool = False, +): + if verbose: + print("JOB " + str(job) + ": range " + str(list(replicaID_range))) for replicaID in replicaID_range: use_tre_file_paths, unarchived_files = find_and_unarchive_tar_files(tre_files[replicaID], verbose=verbose) - if (verbose): print("FILES: ", use_tre_file_paths) - if (verbose): print("Archs:", unarchived_files) + if verbose: + print("FILES: ", use_tre_file_paths) + if verbose: + print("Archs:", unarchived_files) out_path = out_prefix + str(replicaID) + ".tre" compressed_tre = out_path + ".gz" - if (os.path.exists(compressed_tre)): + if os.path.exists(compressed_tre): warnings.warn("Skipped generating .tre.gz file as I found: " + out_path) else: - if (os.path.exists(out_path)): + if os.path.exists(out_path): warnings.warn("Skipped generating .tre file as I found: " + out_path + "\n\t Continue Compressing.") else: tre_file = tre.Tre(use_tre_file_paths[0]) - if verbose: print("JOB " + str(job) + ": parsing " + os.path.basename(use_tre_file_paths[0])) - if (len(use_tre_file_paths) > 1): + if verbose: + print("JOB " + str(job) + ": parsing " + os.path.basename(use_tre_file_paths[0])) + if len(use_tre_file_paths) > 1: for tre_file_path in use_tre_file_paths[1:]: - if verbose: print("JOB " + str(job) + ": append " + os.path.basename(tre_file_path)) + if verbose: + print("JOB " + str(job) + ": append " + os.path.basename(tre_file_path)) tre_file += tre.Tre(tre_file_path) - if verbose: print("JOB " + str(job) + ": write out " + os.path.basename(out_path)) + if verbose: + print("JOB " + str(job) + ": write out " + os.path.basename(out_path)) tre_file.write(out_path) bash.wait_for_fileSystem(out_path) - if verbose: print("JOB " + str(job) + ": done " + os.path.basename(out_path)) + if verbose: + print("JOB " + str(job) + ": done " + os.path.basename(out_path)) del tre_file - if verbose: print("JOB " + str(job) + ": compress " + os.path.basename(out_path)) + if verbose: + print("JOB " + str(job) + ": compress " + os.path.basename(out_path)) compressed_tre = bash.compress_gzip(out_path, out_path=compressed_tre) - if (verbose): print("JOB " + str(job) + ": " + "compress " + compressed_tre + "\t DONE\n") + if verbose: + print("JOB " + str(job) + ": " + "compress " + compressed_tre + "\t DONE\n") # file cleaning: for file_path in use_tre_file_paths: @@ -120,48 +165,69 @@ def _thread_worker_cat_tre(job: int, replicaID_range: (Iterable, List[int]), tre out_tres.update({replicaID: compressed_tre}) -def thread_worker_concat_repdat(job: int, repdat_file_out_path: str, repdat_file_paths: (str, List[str]), - verbose: bool = False) -> str: - if (os.path.exists(repdat_file_out_path)): +def thread_worker_concat_repdat( + job: int, repdat_file_out_path: str, repdat_file_paths: (str, List[str]), verbose: bool = False +) -> str: + if os.path.exists(repdat_file_out_path): warnings.warn("Skipped repdat creation as already existed!: " + repdat_file_out_path) else: - if verbose: print("JOB " + str(job) + ": Found repdats: " + str(repdat_file_paths)) # verbose_repdat - if (isinstance(repdat_file_paths, str)): + if verbose: + print("JOB " + str(job) + ": Found repdats: " + str(repdat_file_paths)) # verbose_repdat + if isinstance(repdat_file_paths, str): repdat_file_paths = [repdat_file_paths] - if verbose: print("JOB " + str(job) + ": Concatenate repdats: \tSTART") # verbose_repdat + if verbose: + print("JOB " + str(job) + ": Concatenate repdats: \tSTART") # verbose_repdat repdat_file = repdat.Repdat(repdat_file_paths.pop(0)) # repdat Class for repdat_path in repdat_file_paths: - if verbose: print("JOB " + str(job) + ": concat:\t", repdat_path) + if verbose: + print("JOB " + str(job) + ": concat:\t", repdat_path) tmp_repdat_file = repdat.Repdat(repdat_path) repdat_file.append(tmp_repdat_file) del tmp_repdat_file - if verbose: print("JOB " + str(job) + ": Concatenate repdats: \tDONE") # verbose_repdat - if verbose: print("JOB " + str(job) + ": Write out repdat: " + str(repdat_file_out_path)) # verbose_repdat + if verbose: + print("JOB " + str(job) + ": Concatenate repdats: \tDONE") # verbose_repdat + if verbose: + print("JOB " + str(job) + ": Write out repdat: " + str(repdat_file_out_path)) # verbose_repdat repdat_file.write(repdat_file_out_path) del repdat_file def _thread_worker_cnfs(job, out_cnfs, in_cnfs, replica_range, out_folder, verbose: bool = False): - if (verbose): print("JOB: " + str(job) + " copy to " + out_folder) + if verbose: + print("JOB: " + str(job) + " copy to " + out_folder) for replicaID in replica_range: - out_cnfs.update({replicaID: bash.copy_file(in_cnfs[replicaID][-1], - out_folder + "/" + os.path.basename(in_cnfs[replicaID][-1]))}) - - -def _thread_worker_conv_trc(job: int, replica_range: Iterable[int], trc_files: List[str], in_topology_path: str, - gromos_path: str, out_traj: dict, - fit_traj_to_mol: int = 1, boundary_conditions: str = "r", - verbose: bool = False): - if (verbose): print("JOB: " + str(job) + " RANGE\t" + str(replica_range)) + out_cnfs.update( + { + replicaID: bash.copy_file( + in_cnfs[replicaID][-1], out_folder + "/" + os.path.basename(in_cnfs[replicaID][-1]) + ) + } + ) + + +def _thread_worker_conv_trc( + job: int, + replica_range: Iterable[int], + trc_files: List[str], + in_topology_path: str, + gromos_path: str, + out_traj: dict, + fit_traj_to_mol: int = 1, + boundary_conditions: str = "r", + verbose: bool = False, +): + if verbose: + print("JOB: " + str(job) + " RANGE\t" + str(replica_range)) gromPP = gromosPP.GromosPP(gromos_path) first = True import mdtraj + start_dir = os.getcwd() for replicaID in replica_range: trc_path = trc_files[replicaID] - if (first): + if first: temp = tempfile.mkdtemp(suffix="_job" + str(job), prefix="convert_", dir=os.path.dirname(trc_path)) os.chdir(temp) first = False @@ -169,47 +235,70 @@ def _thread_worker_conv_trc(job: int, replica_range: Iterable[int], trc_files: L unarchived = False use_trc = trc_path - if (verbose): print("using trc:", use_trc) + if verbose: + print("using trc:", use_trc) out_top_path = use_trc.replace(".trc", "_last.pdb").replace(".gz", "") out_traj_path = use_trc.replace(".trc", ".dcd").replace(".gz", "") out_traj.update({replicaID: {"top": out_top_path, "traj": out_traj_path}}) - if (os.path.exists(out_top_path) and os.path.exists(out_traj_path)): + if os.path.exists(out_top_path) and os.path.exists(out_traj_path): warnings.warn("Found already the traj and its top!:" + out_traj_path) continue - if verbose: print( - "JOB " + str(job) + ": Converting trc_path to -> " + use_trc.replace("trc", "pdb").replace(".tar.gz", "")) - pdb = gromPP.frameout(in_top_path=in_topology_path, in_coord_path=use_trc, - periodic_boundary_condition=boundary_conditions, - gather="cog", out_file_format="pdb", - atomsfit=str(fit_traj_to_mol) + ":a", single_file=True, - out_file_path=use_trc.replace("trc", "pdb").replace("tar", "").replace(".gz", "")) - - if verbose: print("JOB " + str(job) + ": loading pdb : " + pdb) + if verbose: + print( + "JOB " + + str(job) + + ": Converting trc_path to -> " + + use_trc.replace("trc", "pdb").replace(".tar.gz", "") + ) + pdb = gromPP.frameout( + in_top_path=in_topology_path, + in_coord_path=use_trc, + periodic_boundary_condition=boundary_conditions, + gather="cog", + out_file_format="pdb", + atomsfit=str(fit_traj_to_mol) + ":a", + single_file=True, + out_file_path=use_trc.replace("trc", "pdb").replace("tar", "").replace(".gz", ""), + ) + + if verbose: + print("JOB " + str(job) + ": loading pdb : " + pdb) traj = mdtraj.load_pdb(pdb) - if verbose: print("JOB " + str(job) + ": write out data to " + use_trc.replace(".trc", ".dcd/.pdb")) + if verbose: + print("JOB " + str(job) + ": write out data to " + use_trc.replace(".trc", ".dcd/.pdb")) traj.save(out_traj_path) traj[0].save(out_top_path) del traj - if (verbose): print("Done writing out") + if verbose: + print("Done writing out") bash.remove_file(pdb) - if (unarchived): - if (verbose): print("Clean unarchiving") + if unarchived: + if verbose: + print("Clean unarchiving") bash.remove_file(use_trc) bash.remove_folder(temp) os.chdir(start_dir) -def thread_worker_isolate_energies(in_en_file_paths: str, - out_folder: str, - properties: List[str], replicas: List[int], - in_ene_ana_lib: str, gromosPP_path: str, - out_prefix: str = "", tre_prefix: str = "", time=None, dt=None, job: int = -1, - verbose=True) -> List[str]: +def thread_worker_isolate_energies( + in_en_file_paths: str, + out_folder: str, + properties: List[str], + replicas: List[int], + in_ene_ana_lib: str, + gromosPP_path: str, + out_prefix: str = "", + tre_prefix: str = "", + time=None, + dt=None, + job: int = -1, + verbose=True, +) -> List[str]: """isolate_properties_from_tre This func uses Ene Ana from gromos to isolate potentials from out_tre Files in in_folder generated by reeds. @@ -247,41 +336,55 @@ def thread_worker_isolate_energies(in_en_file_paths: str, os.chdir(temp) # get the potentials from each replica.tre* - if (verbose): print("JOB" + str(job) + ": working with job: " + str(list(replicas))) + if verbose: + print("JOB" + str(job) + ": working with job: " + str(list(replicas))) for replicaID in replicas: in_en_file_path = in_en_file_paths[replicaID] out_suffix = "energies_s" + str(replicaID) out_path = out_folder + "/" + out_prefix + "_" + out_suffix + ".dat" - if (verbose): print("CHECKING: " + out_path) - if (not os.path.exists(out_path)): - if verbose: print("JOB" + str(job) + ":\t" + str(replicaID)) - if (verbose): print("JOB" + str(job) + ":", in_en_file_path) - tmp_out = gromos.ene_ana(in_ene_ana_library_path=in_ene_ana_lib, in_en_file_paths=in_en_file_path, - out_energy_folder_path=out_folder, - out_files_suffix=out_suffix, out_files_prefix=out_prefix, - time=str(time) + " " + str(dt), - in_properties=properties, verbose=verbose, single_file=True, workdir=True) + if verbose: + print("CHECKING: " + out_path) + if not os.path.exists(out_path): + if verbose: + print("JOB" + str(job) + ":\t" + str(replicaID)) + if verbose: + print("JOB" + str(job) + ":", in_en_file_path) + tmp_out = gromos.ene_ana( + in_ene_ana_library_path=in_ene_ana_lib, + in_en_file_paths=in_en_file_path, + out_energy_folder_path=out_folder, + out_files_suffix=out_suffix, + out_files_prefix=out_prefix, + time=str(time) + " " + str(dt), + in_properties=properties, + verbose=verbose, + single_file=True, + workdir=True, + ) result_files.append(tmp_out) bash.remove_file(temp + "/*") # remove logs if succesfull os.chdir(start_dir) bash.remove_folder(temp) - if (verbose): print("JOB" + str(job) + ": DONE") + if verbose: + print("JOB" + str(job) + ": DONE") return result_files def _thread_worker_delete(job: int, file_paths: List[str], verbose: bool = False) -> int: for file_path in file_paths: - if (verbose): print("JOB" + str(job) + " - rm: " + file_path + "") + if verbose: + print("JOB" + str(job) + " - rm: " + file_path + "") bash.remove_file(file_path) return 0 def _thread_worker_compress(job: int, in_file_paths: List[str], verbose: bool = False) -> int: for file_path in in_file_paths: - if (verbose): print("JOB" + str(job) + " - gz: " + file_path) + if verbose: + print("JOB" + str(job) + " - gz: " + file_path) bash.compress_gzip(in_path=file_path, verbose=verbose) return 0 @@ -296,44 +399,53 @@ def find_and_unarchive_tar_files(trc_files: List[str], verbose: bool = False): archived_files = list(filter(lambda x: (".tar" in x or ".gz" in x or ".tar.gz" in x), trc_files)) not_archived_files = list(filter(lambda x: not ("tar" in x or ".gz" in x or ".tar.gz" in x), trc_files)) unarchived_files = [] - if (verbose): print("archives: ", archived_files) - if (verbose): print("narchives: ", not_archived_files) + if verbose: + print("archives: ", archived_files) + if verbose: + print("narchives: ", not_archived_files) # untar files: for tared_file in archived_files: - if (len(not_archived_files) == 0 or not any([noAfile in tared_file for noAfile in not_archived_files])): + if len(not_archived_files) == 0 or not any([noAfile in tared_file for noAfile in not_archived_files]): try: # print("Ungzip ->\t", tared_file) - out_path = bash.compress_gzip(in_path=tared_file, - out_path=tared_file.replace(".tar", "").replace(".gz", ""), extract=True) + out_path = bash.compress_gzip( + in_path=tared_file, out_path=tared_file.replace(".tar", "").replace(".gz", ""), extract=True + ) except: # print("Failed gzip, trying tar") - out_path = bash.extract_tar(in_path=tared_file, - out_path=tared_file.replace(".tar", "").replace(".gz", ""), - gunzip_compression=True) + out_path = bash.extract_tar( + in_path=tared_file, + out_path=tared_file.replace(".tar", "").replace(".gz", ""), + gunzip_compression=True, + ) # fix for stupid taring! #todo: remove part - if (any(["cluster" == xfile for xfile in os.listdir(os.path.dirname(tared_file))]) and not os.path.exists( - out_path)): + if any(["cluster" == xfile for xfile in os.listdir(os.path.dirname(tared_file))]) and not os.path.exists( + out_path + ): nfound = True for cpath, tdir, files in os.walk(os.path.dirname(tared_file) + "/cluster"): - if (os.path.basename(tared_file).replace(".tar", "").replace(".gz", "") in files): - if (verbose): print("FOUND PATH: ", - cpath + "/" + os.path.basename(tared_file).replace(".tar", "").replace( - ".gz", "")) + if os.path.basename(tared_file).replace(".tar", "").replace(".gz", "") in files: + if verbose: + print( + "FOUND PATH: ", + cpath + "/" + os.path.basename(tared_file).replace(".tar", "").replace(".gz", ""), + ) wrong_path = cpath + "/" + os.path.basename(tared_file).replace(".tar", "").replace(".gz", "") out_file = bash.move_file(wrong_path, tared_file.replace(".tar", "").replace(".gz", "")) unarchived_files.append(out_file) nfound = False break - if (nfound): + if nfound: raise IOError("could not find untarred file!") else: unarchived_files.append(out_path) # raise Exception("this tar needs special treatment as it is in cluster/yadda/yadda/fun.trc") else: - if (verbose): print([noAfile for noAfile in not_archived_files if (noAfile in tared_file)]) + if verbose: + print([noAfile for noAfile in not_archived_files if (noAfile in tared_file)]) new_files = not_archived_files new_files.extend(unarchived_files) @@ -341,9 +453,14 @@ def find_and_unarchive_tar_files(trc_files: List[str], verbose: bool = False): return use_tre_file_paths, unarchived_files -def gather_simulation_replica_file_paths(in_folder: str, replicas: int, filePrefix: str = "", - fileSuffixes: Union[str, List[str]] = [".tre", ".tre.tar.gz"], - verbose: bool = False, finalNumberingSort=False) -> Dict[int, List[str]]: +def gather_simulation_replica_file_paths( + in_folder: str, + replicas: int, + filePrefix: str = "", + fileSuffixes: Union[str, List[str]] = [".tre", ".tre.tar.gz"], + verbose: bool = False, + finalNumberingSort=False, +) -> Dict[int, List[str]]: """gather_replica_file_paths Finds all trajectory paths in a simulation folder and sorts them by replica. @@ -367,7 +484,7 @@ def gather_simulation_replica_file_paths(in_folder: str, replicas: int, filePref """ - if (isinstance(fileSuffixes, str)): + if isinstance(fileSuffixes, str): fileSuffixes = [fileSuffixes] # browse folders @@ -376,59 +493,74 @@ def gather_simulation_replica_file_paths(in_folder: str, replicas: int, filePref for replica in range(1, replicas + 1): files.update({replica: []}) - if (verbose): print("SEARCH PATTERN: " + filePrefix + " + * +" + str(fileSuffixes)) + if verbose: + print("SEARCH PATTERN: " + filePrefix + " + * +" + str(fileSuffixes)) for dirname, dirnames, filenames in os.walk(in_folder): - if (str(dirname[-1]).isdigit() and os.path.basename(dirname).startswith("eq")): + if str(dirname[-1]).isdigit() and os.path.basename(dirname).startswith("eq"): continue # check actual in_dir for fle pattern - tmp_files = [file for file in filenames if - (filePrefix in file and any([suffix in file for suffix in fileSuffixes]))] + tmp_files = [ + file for file in filenames if (filePrefix in file and any([suffix in file for suffix in fileSuffixes])) + ] if len(tmp_files) != 0: for x in range(1, replicas + 1): - grom_file_prefix = sorted([dirname + "/" + file for file in tmp_files if - (any(["_" + str(x) + suffix in file for suffix in fileSuffixes]))]) + grom_file_prefix = sorted( + [ + dirname + "/" + file + for file in tmp_files + if (any(["_" + str(x) + suffix in file for suffix in fileSuffixes])) + ] + ) files[x] += grom_file_prefix - if verbose: print("walking to in_dir: ", os.path.basename(dirname), "found: ", len(tmp_files)) + if verbose: + print("walking to in_dir: ", os.path.basename(dirname), "found: ", len(tmp_files)) - if (not finalNumberingSort): + if not finalNumberingSort: # final_cleanup for x in files: files[x].sort(key=lambda x: int(x.split("_")[-2])) - if (verbose): + if verbose: print("\nfoundFiles:\n") for x in sorted(files): print("\n" + str(x)) print("\t" + "\t".join([y + "\n" for y in files[x]])) - if (len(files[1]) == 0): + if len(files[1]) == 0: raise ValueError("could not find any file with the prefix: " + filePrefix + " in folder : \n" + in_folder) return files -def gather_simulation_file_paths(in_folder: str, filePrefix: str = "", - fileSuffixes: Union[str, List[str]] = [".tre", ".tre.tar.gz"], - files_per_folder: int = 1, verbose: bool = False) -> List[str]: +def gather_simulation_file_paths( + in_folder: str, + filePrefix: str = "", + fileSuffixes: Union[str, List[str]] = [".tre", ".tre.tar.gz"], + files_per_folder: int = 1, + verbose: bool = False, +) -> List[str]: files = [] - if (isinstance(fileSuffixes, str)): + if isinstance(fileSuffixes, str): fileSuffixes = [fileSuffixes] - if (verbose): print("SEARCH PATTERN: " + filePrefix + " + * +" + str(fileSuffixes)) + if verbose: + print("SEARCH PATTERN: " + filePrefix + " + * +" + str(fileSuffixes)) for dirname, dirnames, filenames in os.walk(in_folder): - if (str(dirname[-1]).isdigit() and os.path.basename(dirname).startswith("eq")): + if str(dirname[-1]).isdigit() and os.path.basename(dirname).startswith("eq"): continue # check actual in_dir for fle pattern - tmp_files = [file for file in filenames if - (filePrefix in file and any([suffix in file for suffix in fileSuffixes]))] + tmp_files = [ + file for file in filenames if (filePrefix in file and any([suffix in file for suffix in fileSuffixes])) + ] - if (len(tmp_files) == files_per_folder): + if len(tmp_files) == files_per_folder: files.extend(list(map(lambda x: dirname + "/" + x, tmp_files))) - if verbose: print("walking to in_dir: ", os.path.basename(dirname), "found: ", len(tmp_files)) + if verbose: + print("walking to in_dir: ", os.path.basename(dirname), "found: ", len(tmp_files)) try: keys = [[int(y) for y in x.split("_") if (y.isdecimal())][-1] for x in files] @@ -437,11 +569,11 @@ def gather_simulation_file_paths(in_folder: str, filePrefix: str = "", warnings.warn("Files are not all enumerated! no file sorting.") sorted_files = files - if (verbose): + if verbose: print("\nfoundFiles:\n") print("\t" + "\n\t".join(sorted_files)) - if (len(sorted_files) == 0): + if len(sorted_files) == 0: raise ValueError("could not find any file with the prefix: " + filePrefix + " in folder : \n" + in_folder) return sorted_files @@ -450,16 +582,18 @@ def gather_simulation_file_paths(in_folder: str, filePrefix: str = "", """ ENERGY FILE FUNCTIONS """ + + def find_header(path: str) -> int: comment_lines = -1 with open(path, "r") as file: for line in file.readlines(): - if (line.strip().startswith("#")): + if line.strip().startswith("#"): comment_lines += 1 continue else: break - if (comment_lines == -1): + if comment_lines == -1: return 0 return comment_lines @@ -481,7 +615,8 @@ def parse_csv_energy_trajectory(in_ene_traj_path: str, verbose: bool = False) -> pd.DataFrame return a pandas data frame containing all energies """ - if (verbose): print("deal with: ", in_ene_traj_path) + if verbose: + print("deal with: ", in_ene_traj_path) ene_traj = pd.read_csv(in_ene_traj_path, header=find_header(in_ene_traj_path), delim_whitespace=True) ene_traj.columns = [x.replace("#", "").strip() for x in ene_traj.columns] setattr(ene_traj, "in_path", in_ene_traj_path) @@ -507,23 +642,28 @@ def parse_csv_energy_trajectories(in_folder: str, ene_trajs_prefix: str, verbose return a list with pandas data frames containing all energy infos. """ - if (verbose): print("SEARCH: ", in_folder + "/" + ene_trajs_prefix + "*.dat") - in_ene_traj_paths = sorted(glob.glob(in_folder + "/" + ene_trajs_prefix + "*.dat"), - key=lambda x: int(x.split("_")[-1].split(".")[0].replace("s", ""))) + if verbose: + print("SEARCH: ", in_folder + "/" + ene_trajs_prefix + "*.dat") + in_ene_traj_paths = sorted( + glob.glob(in_folder + "/" + ene_trajs_prefix + "*.dat"), + key=lambda x: int(x.split("_")[-1].split(".")[0].replace("s", "")), + ) ene_trajs: List[pd.DataFrame] = [] - if (verbose): print("FOUND: ", "\n".join(in_ene_traj_paths)) + if verbose: + print("FOUND: ", "\n".join(in_ene_traj_paths)) for in_ene_traj_path in in_ene_traj_paths: ene_traj = parse_csv_energy_trajectory(in_ene_traj_path, verbose=verbose) - if (verbose): print("csv columns: \t", ene_traj.columns) + if verbose: + print("csv columns: \t", ene_traj.columns) # note: the previous version created problems for filenames which contained periods - #setattr(ene_traj, "s", ((ene_traj.in_path.split("."))[0]).split("_")[-1]) - #setattr(ene_traj, "replicaID", int(((ene_traj.in_path.split("."))[0]).split("_")[-1].replace("s", ""))) + # setattr(ene_traj, "s", ((ene_traj.in_path.split("."))[0]).split("_")[-1]) + # setattr(ene_traj, "replicaID", int(((ene_traj.in_path.split("."))[0]).split("_")[-1].replace("s", ""))) setattr(ene_traj, "s", ((ene_traj.in_path.split("."))[-2]).split("_")[-1]) setattr(ene_traj, "replicaID", int(((ene_traj.in_path.split("."))[-2]).split("_")[-1].replace("s", ""))) ene_trajs.append(ene_traj) - if (len(ene_trajs) == 0): + if len(ene_trajs) == 0: raise ValueError("could not find any energy_trajectory in: ", in_folder + "/" + ene_trajs_prefix + "*.dat") ene_trajs = list(sorted(ene_trajs, key=lambda x: int(x.s.replace("s", "")))) @@ -533,16 +673,29 @@ def parse_csv_energy_trajectories(in_folder: str, ene_trajs_prefix: str, verbose """ concatenation wrapper """ -def project_concatenation(in_folder: str, in_topology_path: str, in_imd: str, num_replicas: int, - control_dict: Dict[str, bool], - out_folder: str, in_ene_ana_lib_path: str, - out_file_prefix: str = "test", - fit_traj_to_mol: int = 1, starting_time: float = 0, include_water_in_trc=True, - additional_properties: Union[Tuple[str], List[str]] = ("solvtemp2", "totdisres"), - n_processes: int = 1, - gromosPP_bin_dir: str = None, verbose: bool = False, nofinal=False, - boundary_conditions: str = "r cog") -> dict: - if (verbose): print("reading imd file: " + in_imd) + + +def project_concatenation( + in_folder: str, + in_topology_path: str, + in_imd: str, + num_replicas: int, + control_dict: Dict[str, bool], + out_folder: str, + in_ene_ana_lib_path: str, + out_file_prefix: str = "test", + fit_traj_to_mol: int = 1, + starting_time: float = 0, + include_water_in_trc=True, + additional_properties: Union[Tuple[str], List[str]] = ("solvtemp2", "totdisres"), + n_processes: int = 1, + gromosPP_bin_dir: str = None, + verbose: bool = False, + nofinal=False, + boundary_conditions: str = "r cog", +) -> dict: + if verbose: + print("reading imd file: " + in_imd) imd_file = imd.Imd(in_imd) dt = float(imd_file.STEP.DT) @@ -550,54 +703,82 @@ def project_concatenation(in_folder: str, in_topology_path: str, in_imd: str, nu dt_tre = int(imd_file.WRITETRAJ.NTWE) * dt tmp_dir = out_folder + "/tmp_file" - if (os.path.isdir(tmp_dir)): + if os.path.isdir(tmp_dir): bash.make_folder(tmp_dir) out_cnfs = out_tres = out_trcs = out_dcd = out_repdat = None p_conv = p_cnf = p_repdat = p_trc = p_tre = p_ene_ana = False submitted_trc_job = submitted_tre_job = False - if (n_processes > 1): + if n_processes > 1: p = mult.Pool(n_processes) manager = mult.Manager() - if (control_dict["cp_cnf"]): - if (verbose): print("\tStart cnfs") + if control_dict["cp_cnf"]: + if verbose: + print("\tStart cnfs") # find all cnf files in this project - sim_dir_cnfs = gather_simulation_replica_file_paths(in_folder, num_replicas, filePrefix="", fileSuffixes=".cnf", - verbose=verbose, finalNumberingSort=nofinal) + sim_dir_cnfs = gather_simulation_replica_file_paths( + in_folder, num_replicas, filePrefix="", fileSuffixes=".cnf", verbose=verbose, finalNumberingSort=nofinal + ) # do parallel - if (n_processes > 1): + if n_processes > 1: out_cnfs = manager.dict() - distribute = [(n, out_cnfs, sim_dir_cnfs, range(n, len(sim_dir_cnfs) + 1, n_processes), out_folder, verbose) - for n in range(1, n_processes + 1)] + distribute = [ + (n, out_cnfs, sim_dir_cnfs, range(n, len(sim_dir_cnfs) + 1, n_processes), out_folder, verbose) + for n in range(1, n_processes + 1) + ] # _async p_cnf = p.starmap(_thread_worker_cnfs, distribute) else: out_cnfs = {} - _thread_worker_cnfs(job=-1, out_cnfs=out_cnfs, in_cnfs=sim_dir_cnfs, - replica_range=list(sim_dir_cnfs.keys()), out_folder=out_folder, verbose=verbose) - if (verbose): print("Out cnfs: ", out_cnfs) - - if (control_dict["cat_trc"]): + _thread_worker_cnfs( + job=-1, + out_cnfs=out_cnfs, + in_cnfs=sim_dir_cnfs, + replica_range=list(sim_dir_cnfs.keys()), + out_folder=out_folder, + verbose=verbose, + ) + if verbose: + print("Out cnfs: ", out_cnfs) + + if control_dict["cat_trc"]: print("\tStart Trc Cat") # find all trc files in this project - trc_files = gather_simulation_replica_file_paths(in_folder, num_replicas, filePrefix="", - fileSuffixes=[".trc", ".trc.gz", ".trc.tar.gz"], - verbose=verbose, - finalNumberingSort=nofinal) + trc_files = gather_simulation_replica_file_paths( + in_folder, + num_replicas, + filePrefix="", + fileSuffixes=[".trc", ".trc.gz", ".trc.tar.gz"], + verbose=verbose, + finalNumberingSort=nofinal, + ) out_prefix = out_folder + "/" + out_file_prefix + "_" # concat all files to a single .trc - if (n_processes > 1): # parallel + if n_processes > 1: # parallel submitted_trc_job = True - if (verbose): print("going parallel: n_processes - " + str(n_processes)) + if verbose: + print("going parallel: n_processes - " + str(n_processes)) out_trcs = manager.dict() distributed_jobs = [ - (n, range(n, len(trc_files) + 1, n_processes), trc_files, out_prefix, in_topology_path, out_trcs, - dt_trc, starting_time, verbose, include_water_in_trc) for n in range(1, n_processes + 1)] + ( + n, + range(n, len(trc_files) + 1, n_processes), + trc_files, + out_prefix, + in_topology_path, + out_trcs, + dt_trc, + starting_time, + verbose, + include_water_in_trc, + ) + for n in range(1, n_processes + 1) + ] # _async p_trc = p.starmap(_thread_worker_cat_trc, distributed_jobs) p.close() @@ -605,107 +786,189 @@ def project_concatenation(in_folder: str, in_topology_path: str, in_imd: str, nu else: out_trcs = {} - _thread_worker_cat_trc(job=-1, topology_path=in_topology_path, replicaID_range=list(trc_files.keys()), - trc_files=trc_files, out_prefix=out_prefix, dt=dt_trc, time=starting_time, - out_trcs=out_trcs, - verbose=verbose, boundary_conditions=boundary_conditions, - include_all=include_water_in_trc) - - if (control_dict["cat_tre"]): + _thread_worker_cat_trc( + job=-1, + topology_path=in_topology_path, + replicaID_range=list(trc_files.keys()), + trc_files=trc_files, + out_prefix=out_prefix, + dt=dt_trc, + time=starting_time, + out_trcs=out_trcs, + verbose=verbose, + boundary_conditions=boundary_conditions, + include_all=include_water_in_trc, + ) + + if control_dict["cat_tre"]: print("\tStart Tre Cat") # find all trc files in this project - tre_files = gather_simulation_replica_file_paths(in_folder, num_replicas, filePrefix="", - fileSuffixes=[".tre", ".tre.tar.gz"], verbose=verbose, - finalNumberingSort=nofinal) + tre_files = gather_simulation_replica_file_paths( + in_folder, + num_replicas, + filePrefix="", + fileSuffixes=[".tre", ".tre.tar.gz"], + verbose=verbose, + finalNumberingSort=nofinal, + ) out_prefix = out_folder + "/" + out_file_prefix + "_" # concat all files to a single .trc - if (n_processes > 1): - if (verbose): print("going parallel: n_processes - " + str(n_processes), " for ", len(tre_files)) + if n_processes > 1: + if verbose: + print("going parallel: n_processes - " + str(n_processes), " for ", len(tre_files)) submitted_tre_job = True out_tres = manager.dict() - distributed_jobs = [(n, range(n, len(tre_files) + 1, n_processes), tre_files, out_prefix, out_tres, verbose) - for n in range(1, n_processes + 1)] + distributed_jobs = [ + (n, range(n, len(tre_files) + 1, n_processes), tre_files, out_prefix, out_tres, verbose) + for n in range(1, n_processes + 1) + ] p = mult.Pool(n_processes) p_tre = p.starmap(_thread_worker_cat_tre, distributed_jobs) p.close() p.join() else: out_tres = {} - _thread_worker_cat_tre(job=-1, replicaID_range=tre_files.keys(), tre_files=tre_files, out_prefix=out_prefix, - out_tres=out_tres, verbose=verbose) - - if (control_dict["ene_ana"]): + _thread_worker_cat_tre( + job=-1, + replicaID_range=tre_files.keys(), + tre_files=tre_files, + out_prefix=out_prefix, + out_tres=out_tres, + verbose=verbose, + ) + + if control_dict["ene_ana"]: print("\tStart ene ana") # wait for async job creating the trcs. - if (submitted_tre_job): + if submitted_tre_job: p_tre.wait() # gather potentials properties = list(additional_properties) # find all trc files in this project - tre_files = gather_simulation_replica_file_paths(in_folder, num_replicas, filePrefix="", - fileSuffixes=[".tre", ".tre.gz"], verbose=verbose, - finalNumberingSort=nofinal) # ".tre.tar.gz" + tre_files = gather_simulation_replica_file_paths( + in_folder, + num_replicas, + filePrefix="", + fileSuffixes=[".tre", ".tre.gz"], + verbose=verbose, + finalNumberingSort=nofinal, + ) # ".tre.tar.gz" # isolate potentials - if verbose: print("Isolate ene_ana:") - if (n_processes > 1): + if verbose: + print("Isolate ene_ana:") + if n_processes > 1: p = mult.Pool(n_processes) distribute_jobs = [ - (out_folder, out_folder, properties, list(tre_files.keys())[n::n_processes], in_ene_ana_lib_path, - gromosPP_bin_dir, out_file_prefix, "", dt_tre, n, verbose) for n in range(n_processes)] + ( + out_folder, + out_folder, + properties, + list(tre_files.keys())[n::n_processes], + in_ene_ana_lib_path, + gromosPP_bin_dir, + out_file_prefix, + "", + dt_tre, + n, + verbose, + ) + for n in range(n_processes) + ] p_ene_ana = p.starmap_async(thread_worker_isolate_energies, distribute_jobs) else: - thread_worker_isolate_energies(in_en_file_paths=tre_files, out_folder=out_folder, properties=properties, - out_prefix=out_file_prefix, - in_ene_ana_lib=in_ene_ana_lib_path, - gromosPP_path=gromosPP_bin_dir, dt=dt_tre, - replicas=list(tre_files.keys()), verbose=verbose) - - if (control_dict["convert_trcs"]): + thread_worker_isolate_energies( + in_en_file_paths=tre_files, + out_folder=out_folder, + properties=properties, + out_prefix=out_file_prefix, + in_ene_ana_lib=in_ene_ana_lib_path, + gromosPP_path=gromosPP_bin_dir, + dt=dt_tre, + replicas=list(tre_files.keys()), + verbose=verbose, + ) + + if control_dict["convert_trcs"]: print("\tStart Trc Conversion") # wait for async job creating the trcs. - if (submitted_trc_job): + if submitted_trc_job: p_trc.wait() # get files: final_trc_files = list( - sorted(glob.glob(out_folder + "/*.trc*"), key=lambda x: int(x.split("_")[-1].split(".")[0]))) + sorted(glob.glob(out_folder + "/*.trc*"), key=lambda x: int(x.split("_")[-1].split(".")[0])) + ) - if (n_processes > 1): + if n_processes > 1: out_dcd = manager.dict() distributed_jobs = [ - (n, range(n, num_replicas, n_processes), final_trc_files, in_topology_path, gromosPP_bin_dir, out_dcd, - fit_traj_to_mol, verbose) for - n in range(n_processes)] + ( + n, + range(n, num_replicas, n_processes), + final_trc_files, + in_topology_path, + gromosPP_bin_dir, + out_dcd, + fit_traj_to_mol, + verbose, + ) + for n in range(n_processes) + ] p_conv = p.starmap_async(_thread_worker_conv_trc, distributed_jobs) else: out_dcd = {} - _thread_worker_conv_trc(job=-1, replica_range=range(num_replicas), trc_files=final_trc_files, - in_topology_path=in_topology_path, - gromos_path=gromosPP_bin_dir, out_traj=out_dcd, fit_traj_to_mol=1, verbose=verbose, - boundary_conditions=boundary_conditions) - - if (n_processes > 1): + _thread_worker_conv_trc( + job=-1, + replica_range=range(num_replicas), + trc_files=final_trc_files, + in_topology_path=in_topology_path, + gromos_path=gromosPP_bin_dir, + out_traj=out_dcd, + fit_traj_to_mol=1, + verbose=verbose, + boundary_conditions=boundary_conditions, + ) + + if n_processes > 1: # wait for the jobs to finish - if ((not p_conv or p_conv.wait()) and (not p_cnf or p_cnf.wait()) and - (not p_repdat or p_repdat.wait()) and (not p_trc or p_trc.wait()) and - (not p_tre or p_tre.wait()) and (not p_ene_ana or p_ene_ana.wait())): + if ( + (not p_conv or p_conv.wait()) + and (not p_cnf or p_cnf.wait()) + and (not p_repdat or p_repdat.wait()) + and (not p_trc or p_trc.wait()) + and (not p_tre or p_tre.wait()) + and (not p_ene_ana or p_ene_ana.wait()) + ): raise ChildProcessError("A process failed! ") p.close() p.join() - out_dict = {"out_folder": out_folder, "cnfs": dict(out_cnfs), "repdat": out_repdat, "tres": dict(out_tres), - "trcs": dict(out_trcs), "dcds": dict(out_dcd)} + out_dict = { + "out_folder": out_folder, + "cnfs": dict(out_cnfs), + "repdat": out_repdat, + "tres": dict(out_tres), + "trcs": dict(out_trcs), + "dcds": dict(out_dcd), + } manager.shutdown() else: - out_dict = {"out_folder": out_folder, "cnfs": out_cnfs, "repdat": out_repdat, "tres": out_tres, - "trcs": out_trcs, "dcds": out_dcd} - if (verbose): print("all jobs finished") + out_dict = { + "out_folder": out_folder, + "cnfs": out_cnfs, + "repdat": out_repdat, + "tres": out_tres, + "trcs": out_trcs, + "dcds": out_dcd, + } + if verbose: + print("all jobs finished") return out_dict @@ -713,6 +976,7 @@ def project_concatenation(in_folder: str, in_topology_path: str, in_imd: str, nu COMPRESS FUNCTION """ + def compress_files(in_paths: List[str], n_processes: int = 1) -> List[str]: """compress a list of files @@ -722,20 +986,20 @@ def compress_files(in_paths: List[str], n_processes: int = 1) -> List[str]: n_processes: int how many processes can be used in parallel? - + Returns ------- List[str] outpaths """ - if (type(in_paths) == str): + if type(in_paths) == str: in_paths = [in_paths] out_paths = [] # check: for path in in_paths: - if (os.path.exists(path)): + if os.path.exists(path): archive_path = path + ".gz" out_paths.append(archive_path) else: @@ -743,7 +1007,7 @@ def compress_files(in_paths: List[str], n_processes: int = 1) -> List[str]: # do: print("Gen Gzips:") - if (n_processes == 1): + if n_processes == 1: for path in in_paths: bash.compress_gzip(in_path=path, out_path=path + ".gz") else: # do parallel @@ -753,4 +1017,3 @@ def compress_files(in_paths: List[str], n_processes: int = 1) -> List[str]: p.close() p.join() return out_paths - diff --git a/pygromos/simulations/hpc_queuing/job_scheduling/module_functions.py b/pygromos/simulations/hpc_queuing/job_scheduling/module_functions.py index e8d7a7f4..4ff40a9c 100644 --- a/pygromos/simulations/hpc_queuing/job_scheduling/module_functions.py +++ b/pygromos/simulations/hpc_queuing/job_scheduling/module_functions.py @@ -6,8 +6,14 @@ from pygromos.utils import amino_acids as aa -def adapt_imd_template(in_template_imd_path: str, out_imd_dir: str, cnf: cnf_cls.Cnf, exclude_residues: list = [], - simulation_steps: int = 100000, solvent_keyword: str = "SOLV"): +def adapt_imd_template( + in_template_imd_path: str, + out_imd_dir: str, + cnf: cnf_cls.Cnf, + exclude_residues: list = [], + simulation_steps: int = 100000, + solvent_keyword: str = "SOLV", +): """ .. autofunction: modify_imds - for generateOptimizedStates This function prepares the imd. protocol file for a gromos simulation. @@ -16,11 +22,16 @@ def adapt_imd_template(in_template_imd_path: str, out_imd_dir: str, cnf: cnf_cls """ orig_residues = cnf.get_residues() - ignore_residues = lambda res: res != solvent_keyword and res not in aa.three_letter_aa_lib and res != "prot" and ( - not res in exclude_residues) + ignore_residues = ( + lambda res: res != solvent_keyword + and res not in aa.three_letter_aa_lib + and res != "prot" + and (not res in exclude_residues) + ) protein_residues = {res: val for res, val in orig_residues.items() if (res in aa.three_letter_aa_lib)} - n_atoms_prot = sum([sum(list(orig_residues[res].values())) for res in orig_residues if - res in aa.three_letter_aa_lib]) # if protein is present! + n_atoms_prot = sum( + [sum(list(orig_residues[res].values())) for res in orig_residues if res in aa.three_letter_aa_lib] + ) # if protein is present! prot_position = min([min(val) for res, val in protein_residues.items()]) if (n_atoms_prot > 0) else 0 # adapt resis @@ -32,11 +43,11 @@ def adapt_imd_template(in_template_imd_path: str, out_imd_dir: str, cnf: cnf_cls lig_names = [res for res in residues if ignore_residues(res)] lig_position = min([min(residues[res]) for res in residues if ignore_residues(res)]) - if (n_atoms_prot > 1): + if n_atoms_prot > 1: print("protein_position:", prot_position) residues.update({"prot": {prot_position: n_atoms_prot}}) - if (not solvent_keyword in residues): + if not solvent_keyword in residues: residues.update({solvent_keyword: 0}) imd_file = imd.Imd(in_template_imd_path) @@ -46,49 +57,65 @@ def adapt_imd_template(in_template_imd_path: str, out_imd_dir: str, cnf: cnf_cls imd_file.STEP.NSTLIM = simulation_steps # hack for TIP3P explicit solvent - if (len(exclude_residues) > 0 and not "prot" in residues): + if len(exclude_residues) > 0 and not "prot" in residues: solvent_bath = ( - lig_atoms + sum([sum(list(residues[x].values())) for x in exclude_residues]) + - residues[solvent_keyword]) + lig_atoms + sum([sum(list(residues[x].values())) for x in exclude_residues]) + residues[solvent_keyword] + ) temp_baths = {lig_atoms: 1, solvent_bath: 2} # Temperature baths - elif ("prot" in residues): + elif "prot" in residues: temp_baths = {} - if (len(exclude_residues) < 0): # TODO: DIRTY HACK: in PNMT is Cofactor at end of the file. - solvent_bath = (lig_atoms + n_atoms_prot + residues[solvent_keyword]) + if len(exclude_residues) < 0: # TODO: DIRTY HACK: in PNMT is Cofactor at end of the file. + solvent_bath = lig_atoms + n_atoms_prot + residues[solvent_keyword] else: solvent_bath = ( - lig_atoms + n_atoms_prot + sum([sum(list(residues[x].values())) for x in exclude_residues]) + - residues[solvent_keyword]) + lig_atoms + + n_atoms_prot + + sum([sum(list(residues[x].values())) for x in exclude_residues]) + + residues[solvent_keyword] + ) - if (lig_position < prot_position): + if lig_position < prot_position: temp_baths = {lig_atoms: 1, (lig_atoms + n_atoms_prot): 2, solvent_bath: 3} else: temp_baths = {n_atoms_prot: 1, (lig_atoms + n_atoms_prot): 2, solvent_bath: 3} else: - temp_baths = {lig_atoms: 1, (lig_atoms + residues[solvent_keyword]): 2} if (solvent_keyword in residues) else { - lig_atoms: 1} + temp_baths = ( + {lig_atoms: 1, (lig_atoms + residues[solvent_keyword]): 2} + if (solvent_keyword in residues) + else {lig_atoms: 1} + ) - if (not isinstance(imd_file.MULTIBATH, type(None))): + if not isinstance(imd_file.MULTIBATH, type(None)): imd_file.MULTIBATH.adapt_multibath(last_atoms_bath=temp_baths) # edit EDS part imd_template_path = out_imd_dir + "/opt_structs_" + "_".join(lig_names) s_values = [1.0 for x in range(lig_num)] for state, s_values in zip(range(1, lig_num + 1), s_values): - imd_file.edit_EDS(NUMSTATES=lig_num, S=s_values, - EIR=[500 if (x == state) else -500 for x in range(1, lig_num + 1)]) + imd_file.edit_EDS( + NUMSTATES=lig_num, S=s_values, EIR=[500 if (x == state) else -500 for x in range(1, lig_num + 1)] + ) imd_file.write(imd_template_path + "_" + str(state) + ".imd") return imd_template_path, s_values, lig_num -def write_job_script(out_script_path:str, target_function:callable, variable_dict:dict, python_cmd:str= "python3", verbose:bool=False, no_reeds_control_dict:bool=False)->str: - if(not os.path.exists(os.path.dirname(out_script_path))): - raise IOError("Could not find path of dir, that should contain the schedule script!\n\t Got Path: "+out_script_path) - - #Build str: +def write_job_script( + out_script_path: str, + target_function: callable, + variable_dict: dict, + python_cmd: str = "python3", + verbose: bool = False, + no_reeds_control_dict: bool = False, +) -> str: + if not os.path.exists(os.path.dirname(out_script_path)): + raise IOError( + "Could not find path of dir, that should contain the schedule script!\n\t Got Path: " + out_script_path + ) + + # Build str: s = signature(target_function) import_string = "#IMPORTS\n" import_string += "from " + str(target_function.__module__) + " import " + target_function.__name__ @@ -96,13 +123,13 @@ def write_job_script(out_script_path:str, target_function:callable, variable_dic cmd_options = "" missed_keys = [] - for key in s.parameters: - if( key in variable_dict): - value=variable_dict[key] - if (key == "in_simSystem"): # this is a nasty way! ... tends to fail! + for key in s.parameters: + if key in variable_dict: + value = variable_dict[key] + if key == "in_simSystem": # this is a nasty way! ... tends to fail! sys = value vars_string += sys.get_script_generation_command(var_name=key, var_prefixes="system") - #elif(isinstance(value, Dict)): + # elif(isinstance(value, Dict)): # if(key == "control_dict"): # if(no_reeds_control_dict): # vars_string += reeds_analysis.dict_to_nice_string(value) @@ -110,26 +137,31 @@ def write_job_script(out_script_path:str, target_function:callable, variable_dic # vars_string += reeds_analysis.dict_to_nice_string(reeds_analysis.check_script_control(value)) # else: # vars_string += reeds_analysis.dict_to_nice_string(value) - elif(isinstance(value, List)): + elif isinstance(value, List): vars_string += key + "= [ " + ", ".join(map(str, value)) + "]\n" - elif(isinstance(value, str)): - vars_string += key + " = \"" + str(value) + "\"\n" + elif isinstance(value, str): + vars_string += key + ' = "' + str(value) + '"\n' else: vars_string += key + " = " + str(value) + "\n" - cmd_options += key + "=" + key + ", " - elif(s.parameters[key].default == _empty): + cmd_options += key + "=" + key + ", " + elif s.parameters[key].default == _empty: missed_keys.append(key) - if(len(missed_keys)>0): - raise ValueError("Found some variables missing in variable dict,that are required!\n\t"+"\n\t".join(missed_keys)) + if len(missed_keys) > 0: + raise ValueError( + "Found some variables missing in variable dict,that are required!\n\t" + "\n\t".join(missed_keys) + ) cmd_string = "\n#DO\n" cmd_string += target_function.__name__ + "(" + cmd_options + ")" - script_text = "#!/usr/bin/env "+python_cmd+"\n\n" + import_string + "\n\n" + vars_string + "\n\n" + cmd_string + "\n" - if(verbose): print(script_text) + script_text = ( + "#!/usr/bin/env " + python_cmd + "\n\n" + import_string + "\n\n" + vars_string + "\n\n" + cmd_string + "\n" + ) + if verbose: + print(script_text) - #write out file + # write out file out_script_file = open(out_script_path, "w") out_script_file.write(script_text) out_script_file.close() @@ -137,10 +169,15 @@ def write_job_script(out_script_path:str, target_function:callable, variable_dic return out_script_path - -def build_MD_analysis_script(in_simulation_name:str, in_folder:str, in_topology_path: str, - out_dir:str, out_script_path:str, - in_ene_ana_lib:str, gromosPP_path:str): +def build_MD_analysis_script( + in_simulation_name: str, + in_folder: str, + in_topology_path: str, + out_dir: str, + out_script_path: str, + in_ene_ana_lib: str, + gromosPP_path: str, +): """ BAD FUNCTION! HISTORIC RELICT Parameters @@ -165,38 +202,40 @@ def build_MD_analysis_script(in_simulation_name:str, in_folder:str, in_topology_ dependencies_text = "# INPUT DIRS/PATHS\n" dependencies_text += "##binary or file paths\n" - dependencies_text += "in_ene_ana_lib = \""+in_ene_ana_lib+"\"\n" - dependencies_text += "gromosPP_path = \""+gromosPP_path+"\"\n" + dependencies_text += 'in_ene_ana_lib = "' + in_ene_ana_lib + '"\n' + dependencies_text += 'gromosPP_path = "' + gromosPP_path + '"\n' dependencies_text += "\n" dependencies_text += "##dependencies\n" - dependencies_text += "in_simulation_name = \""+in_simulation_name+"\"\n" - dependencies_text += "in_folder = \""+in_folder+"\"\n" - dependencies_text += "in_topology_path = \""+in_topology_path+"\"\n" - dependencies_text += "out_dir = \""+out_dir+"\"\n" + dependencies_text += 'in_simulation_name = "' + in_simulation_name + '"\n' + dependencies_text += 'in_folder = "' + in_folder + '"\n' + dependencies_text += 'in_topology_path = "' + in_topology_path + '"\n' + dependencies_text += 'out_dir = "' + out_dir + '"\n' dependencies_text += "\n" dependencies_text += "##controls\n" dependencies_text += "control_dict = {\n" - dependencies_text += "\"concat\": {\"do\": True,\n" - dependencies_text += "\t\"sub\": {\n" - dependencies_text += "\t\t\"tre\": True,\n" - dependencies_text += "\t\t\"cnf\": True,\n" - dependencies_text += "\t\t\"trc\": True,\n" - dependencies_text += "\t\t\"convert_trc_xtc\": True\n" + dependencies_text += '"concat": {"do": True,\n' + dependencies_text += '\t"sub": {\n' + dependencies_text += '\t\t"tre": True,\n' + dependencies_text += '\t\t"cnf": True,\n' + dependencies_text += '\t\t"trc": True,\n' + dependencies_text += '\t\t"convert_trc_xtc": True\n' dependencies_text += "\t\t}\n" dependencies_text += "\t},\n" - dependencies_text += "\"ene_ana\":{\"do\":True}\n" + dependencies_text += '"ene_ana":{"do":True}\n' dependencies_text += "}\n" dependencies_text += "trc_take_every_step = 1\n" dependencies_text += "\n\n" - command_text = "ana.do(in_simulation_name=in_simulation_name, in_folder=in_folder, " \ - "in_topology_path=in_topology_path, out_dir=out_dir," \ - "in_ene_ana_lib=in_ene_ana_lib, gromosPP_path=gromosPP_path)\n\n" + command_text = ( + "ana.do(in_simulation_name=in_simulation_name, in_folder=in_folder, " + "in_topology_path=in_topology_path, out_dir=out_dir," + "in_ene_ana_lib=in_ene_ana_lib, gromosPP_path=gromosPP_path)\n\n" + ) - script_text = import_text+dependencies_text+command_text + script_text = import_text + dependencies_text + command_text ana_file = open(out_script_path, "w") ana_file.write(script_text) ana_file.close() - return out_script_path \ No newline at end of file + return out_script_path diff --git a/pygromos/simulations/hpc_queuing/job_scheduling/schedulers/scheduler_functions.py b/pygromos/simulations/hpc_queuing/job_scheduling/schedulers/scheduler_functions.py index 6ecf5b57..ce0bf0ad 100644 --- a/pygromos/simulations/hpc_queuing/job_scheduling/schedulers/scheduler_functions.py +++ b/pygromos/simulations/hpc_queuing/job_scheduling/schedulers/scheduler_functions.py @@ -13,65 +13,100 @@ from pygromos.utils.utils import spacer3 -def do_skip_job(tmp_out_cnf: str, simSystem: Gromos_System, - tmp_jobname: str, job_submission_system: _SubmissionSystem, previous_job: int, - verbose: bool = True, verbose_lvl:int = 1): +def do_skip_job( + tmp_out_cnf: str, + simSystem: Gromos_System, + tmp_jobname: str, + job_submission_system: _SubmissionSystem, + previous_job: int, + verbose: bool = True, + verbose_lvl: int = 1, +): # Check if job with same name is already in the queue! - if (verbose) and verbose_lvl >= 2: print("Checking if jobs was already submitted or done") - if (job_submission_system._block_double_submission): # can we find an job with this name in the queue? - if (verbose) and verbose_lvl >= 2: print("Checking for jobs with name: " + tmp_jobname) + if (verbose) and verbose_lvl >= 2: + print("Checking if jobs was already submitted or done") + if job_submission_system._block_double_submission: # can we find an job with this name in the queue? + if (verbose) and verbose_lvl >= 2: + print("Checking for jobs with name: " + tmp_jobname) queued_job_ids = job_submission_system.search_queue_for_jobname(job_name=tmp_jobname) - - if(isinstance(queued_job_ids, (pd.DataFrame, pd.Series))): + + if isinstance(queued_job_ids, (pd.DataFrame, pd.Series)): queued_job_ids = list(queued_job_ids.where(queued_job_ids.STAT.isin(["RUN", "PEND"])).dropna().JOBID) ## check if already submitted - if (len(queued_job_ids) > 1): # check if job is already submitted: - if verbose: print( - "\t\t\tSKIP job Submission: " + tmp_jobname + " was already submitted to the queue! \n\t\t\t\tSKIP\n" - + "\t\t\tsubmitted IDS: " + "\n\t\t\t".join(map(str, queued_job_ids)) + "\n") + if len(queued_job_ids) > 1: # check if job is already submitted: + if verbose: + print( + "\t\t\tSKIP job Submission: " + + tmp_jobname + + " was already submitted to the queue! \n\t\t\t\tSKIP\n" + + "\t\t\tsubmitted IDS: " + + "\n\t\t\t".join(map(str, queued_job_ids)) + + "\n" + ) try: simSystem.cnf = tmp_out_cnf except Exception as err: - raise IOError("Tried to read found cnf file: "+tmp_out_cnf+". FAILED! \n"+str(err.args)) - - if (len(queued_job_ids) == 1): + raise IOError("Tried to read found cnf file: " + tmp_out_cnf + ". FAILED! \n" + str(err.args)) + + if len(queued_job_ids) == 1: previous_job = queued_job_ids[0] - if (verbose) and verbose_lvl >= 2: print("\nTRY to attach next job to ", previous_job, "\n") + if (verbose) and verbose_lvl >= 2: + print("\nTRY to attach next job to ", previous_job, "\n") else: - raise ValueError("\nthere are multiple jobs, that could be the precessor. " + " ".join(map(str, queued_job_ids))) - if (verbose): print(True) - if (verbose): print() + raise ValueError( + "\nthere are multiple jobs, that could be the precessor. " + " ".join(map(str, queued_job_ids)) + ) + if verbose: + print(True) + if verbose: + print() return True, previous_job # Check if run was already finished: tmp_out_cnfs_regex = "_".join(tmp_out_cnf.split("_")[:-1]) + "*.cnf" - if (verbose): print("Checking for resulting files: " + tmp_out_cnfs_regex) + if verbose: + print("Checking for resulting files: " + tmp_out_cnfs_regex) - if (len(glob.glob(tmp_out_cnfs_regex)) > 0): # was this job already run and finished? - if verbose: print( - "\t\t NOT SUBMITTED!(inScript) as these Files were found: \n\t" + tmp_out_cnfs_regex) + if len(glob.glob(tmp_out_cnfs_regex)) > 0: # was this job already run and finished? + if verbose: + print("\t\t NOT SUBMITTED!(inScript) as these Files were found: \n\t" + tmp_out_cnfs_regex) setattr(simSystem, "coord_seeds", tmp_out_cnf) # set next coord Files prefix_command = "" - if (verbose) and verbose_lvl >= 2: print(simSystem.cnf.path) - if (verbose) and verbose_lvl >= 2: print(True) - if (verbose) and verbose_lvl >= 2: print() + if (verbose) and verbose_lvl >= 2: + print(simSystem.cnf.path) + if (verbose) and verbose_lvl >= 2: + print(True) + if (verbose) and verbose_lvl >= 2: + print() return True, None - if (verbose): print(False) - if(verbose): print() + if verbose: + print(False) + if verbose: + print() return False, previous_job -def chain_submission(simSystem:Gromos_System, - out_dir_path: str, out_prefix: str, - chain_job_repetitions: int, worker_script: str, - job_submission_system: _SubmissionSystem, jobname: str, - run_analysis_script_every_x_runs: int = 0, in_analysis_script_path: str = "", - start_run_index: int = 1, - prefix_command: str = "", previous_job_ID: int = None, work_dir: str = None, - initialize_first_run: bool = True, reinitialize_every_run: bool = False, - verbose: bool = False, verbose_lvl:int = 1): +def chain_submission( + simSystem: Gromos_System, + out_dir_path: str, + out_prefix: str, + chain_job_repetitions: int, + worker_script: str, + job_submission_system: _SubmissionSystem, + jobname: str, + run_analysis_script_every_x_runs: int = 0, + in_analysis_script_path: str = "", + start_run_index: int = 1, + prefix_command: str = "", + previous_job_ID: int = None, + work_dir: str = None, + initialize_first_run: bool = True, + reinitialize_every_run: bool = False, + verbose: bool = False, + verbose_lvl: int = 1, +): """ Parameters @@ -101,19 +136,23 @@ def chain_submission(simSystem:Gromos_System, ------- """ - if verbose: print("\nChainSubmission - "+out_prefix+"\n"+"="*30+"\n") - if(verbose) and verbose_lvl >= 2: print("start_run_index " + str(start_run_index)) - if(verbose) and verbose_lvl >= 2: print("job reptitions " + str(chain_job_repetitions)) + if verbose: + print("\nChainSubmission - " + out_prefix + "\n" + "=" * 30 + "\n") + if (verbose) and verbose_lvl >= 2: + print("start_run_index " + str(start_run_index)) + if (verbose) and verbose_lvl >= 2: + print("job reptitions " + str(chain_job_repetitions)) orig_prefix_command = prefix_command - if(not job_submission_system is LOCAL): + if not job_submission_system is LOCAL: simSystem._future_promise = True - ana_id=None + ana_id = None job_submission_system.job_duration = job_submission_system.job_duration for runID in range(start_run_index, chain_job_repetitions + 1): - if verbose: print("\n submit " + jobname + "_" + str(runID) + "\n"+spacer3) + if verbose: + print("\n submit " + jobname + "_" + str(runID) + "\n" + spacer3) tmp_outprefix = out_prefix + "_" + str(runID) tmp_jobname = jobname + "_" + str(runID) @@ -121,23 +160,28 @@ def chain_submission(simSystem:Gromos_System, tmp_out_cnf = tmp_outdir + "/" + tmp_outprefix + ".cnf" # Checks if run should be skipped! - do_skip, previous_job_ID = do_skip_job(tmp_out_cnf=tmp_out_cnf, simSystem=simSystem, - tmp_jobname=tmp_jobname, job_submission_system=job_submission_system, - previous_job=previous_job_ID, verbose=verbose) + do_skip, previous_job_ID = do_skip_job( + tmp_out_cnf=tmp_out_cnf, + simSystem=simSystem, + tmp_jobname=tmp_jobname, + job_submission_system=job_submission_system, + previous_job=previous_job_ID, + verbose=verbose, + ) - if (not do_skip): + if not do_skip: bash.make_folder(tmp_outdir) # build COMMANDS: prefix_command += "" - if(len(prefix_command)>1): + if len(prefix_command) > 1: prefix_command += " && " - - # We will write the arguments to the python script in a bash array - # to make it simpler to read in our input files. - + + # We will write the arguments to the python script in a bash array + # to make it simpler to read in our input files. + md_args = "md_args=(\n" - + md_args += "-out_dir " + tmp_outdir + "\n" md_args += "-in_cnf_path " + simSystem.cnf.path + "\n" md_args += "-in_imd_path " + simSystem.imd.path + "\n" @@ -145,99 +189,120 @@ def chain_submission(simSystem:Gromos_System, md_args += "-runID " + str(runID) + "\n" ## OPTIONAL ARGS - if (not simSystem.disres is None): + if not simSystem.disres is None: md_args += "-in_disres_path " + simSystem.disres.path + "\n" - if (not simSystem.ptp is None): + if not simSystem.ptp is None: md_args += "-in_perttopo_path " + simSystem.ptp.path + "\n" - if (not simSystem.refpos is None): + if not simSystem.refpos is None: md_args += "-in_refpos_path " + simSystem.refpos.path + "\n" - if (not simSystem.qmmm is None): + if not simSystem.qmmm is None: md_args += "-in_qmmm_path " + simSystem.qmmm.path + " " - if (not simSystem.posres is None): + if not simSystem.posres is None: md_args += "-in_posres_path " + simSystem.posres.path + "\n" - + md_args += "-nmpi " + str(job_submission_system.nmpi) + "\n" md_args += "-nomp " + str(job_submission_system.nomp) + "\n" - md_args += "-initialize_first_run "+str(initialize_first_run)+ "\n" - md_args += "-reinitialize_every_run "+str(reinitialize_every_run)+ "\n" + md_args += "-initialize_first_run " + str(initialize_first_run) + "\n" + md_args += "-reinitialize_every_run " + str(reinitialize_every_run) + "\n" if simSystem.gromosXX is not None: md_args += "-gromosXX_bin_dir " + str(simSystem.gromosXX.bin) + "\n" else: md_args += "-gromosXX_bin_dir None \n" if verbose: - warnings.warn("gromosXX_bin_dir is None \n If you want to simulate something please add a existing gromos bin\n") - - if(work_dir is not None): + warnings.warn( + "gromosXX_bin_dir is None \n If you want to simulate something please add a existing gromos bin\n" + ) + + if work_dir is not None: md_args += "-work_dir " + str(work_dir) + "\n" - if(hasattr(simSystem.imd, "WRITETRAJ")): - if(simSystem.imd.WRITETRAJ.NTWX > 0): - md_args += "-out_trc "+str(True)+ "\n" - if(simSystem.imd.WRITETRAJ.NTWE > 0): - md_args += "-out_tre "+str(True)+ "\n" - if(simSystem.imd.WRITETRAJ.NTWV > 0): - md_args += "-out_trv "+str(True)+ "\n" - if(simSystem.imd.WRITETRAJ.NTWF > 0): - md_args += "-out_trf "+str(True)+ "\n" - if(simSystem.imd.WRITETRAJ.NTWG > 0): - md_args += "-out_trg "+str(True)+ "\n" - - if(verbose) and verbose_lvl >= 2: print("COMMAND: ", md_script_command) - + if hasattr(simSystem.imd, "WRITETRAJ"): + if simSystem.imd.WRITETRAJ.NTWX > 0: + md_args += "-out_trc " + str(True) + "\n" + if simSystem.imd.WRITETRAJ.NTWE > 0: + md_args += "-out_tre " + str(True) + "\n" + if simSystem.imd.WRITETRAJ.NTWV > 0: + md_args += "-out_trv " + str(True) + "\n" + if simSystem.imd.WRITETRAJ.NTWF > 0: + md_args += "-out_trf " + str(True) + "\n" + if simSystem.imd.WRITETRAJ.NTWG > 0: + md_args += "-out_trg " + str(True) + "\n" + + if (verbose) and verbose_lvl >= 2: + print("COMMAND: ", md_script_command) + md_args += "-zip_trajectories " + str(job_submission_system.zip_trajectories) + "\n" - md_args += ")\n" # closing the bash array which stores all arguments. - + md_args += ")\n" # closing the bash array which stores all arguments. + # add zip option here - + # MAIN commands md_script_command = prefix_command + "\n\n" + md_args + "\n" - md_script_command += "python3 " + worker_script + " \"${md_args[@]}\" \n" + md_script_command += "python3 " + worker_script + ' "${md_args[@]}" \n' - if verbose: print("PREVIOUS ID: ", previous_job_ID) + if verbose: + print("PREVIOUS ID: ", previous_job_ID) # SCHEDULE THE COMMANDS try: - if (verbose): print("\tSIMULATION") + if verbose: + print("\tSIMULATION") os.chdir(tmp_outdir) - sub_job = Submission_job(command=md_script_command, - jobName=tmp_jobname, - submit_from_dir=tmp_outdir, - queue_after_jobID=previous_job_ID, - outLog=tmp_outdir + "/" + out_prefix + "_md.out", - errLog=tmp_outdir + "/" + out_prefix + "_md.err", - sumbit_from_file=True) + sub_job = Submission_job( + command=md_script_command, + jobName=tmp_jobname, + submit_from_dir=tmp_outdir, + queue_after_jobID=previous_job_ID, + outLog=tmp_outdir + "/" + out_prefix + "_md.out", + errLog=tmp_outdir + "/" + out_prefix + "_md.err", + sumbit_from_file=True, + ) previous_job_ID = job_submission_system.submit_to_queue(sub_job) - if verbose: print("SIMULATION ID: ", previous_job_ID) + if verbose: + print("SIMULATION ID: ", previous_job_ID) except ValueError as err: # job already in the queue - raise ValueError("ERROR during submission of main job "+str(tmp_jobname)+":\n"+"\n".join(err.args)) + raise ValueError( + "ERROR during submission of main job " + str(tmp_jobname) + ":\n" + "\n".join(err.args) + ) # OPTIONAL schedule - analysis inbetween. - if (runID > 1 and run_analysis_script_every_x_runs != 0 and - runID % run_analysis_script_every_x_runs == 0 - and runID < chain_job_repetitions): - - if (verbose) and verbose_lvl >= 2: print("\tINBETWEEN ANALYSIS") - sub_job = Submission_job(command=in_analysis_script_path, - jobName=jobname + "_intermediate_ana_run_" + str(runID), - outLog=tmp_outdir + "/" + out_prefix + "_inbetweenAna.out", - errLog=tmp_outdir + "/" + out_prefix + "_inbetweenAna.err", - queue_after_jobID=previous_job_ID) + if ( + runID > 1 + and run_analysis_script_every_x_runs != 0 + and runID % run_analysis_script_every_x_runs == 0 + and runID < chain_job_repetitions + ): + + if (verbose) and verbose_lvl >= 2: + print("\tINBETWEEN ANALYSIS") + sub_job = Submission_job( + command=in_analysis_script_path, + jobName=jobname + "_intermediate_ana_run_" + str(runID), + outLog=tmp_outdir + "/" + out_prefix + "_inbetweenAna.out", + errLog=tmp_outdir + "/" + out_prefix + "_inbetweenAna.err", + queue_after_jobID=previous_job_ID, + ) try: ana_id = job_submission_system.submit_to_queue(sub_job) - if (verbose) and verbose_lvl >= 2: print("\n") + if (verbose) and verbose_lvl >= 2: + print("\n") except ValueError as err: # job already in the queue - print("ERROR during submission of analysis command of "+sub_job.jobName+":\n") + print("ERROR during submission of analysis command of " + sub_job.jobName + ":\n") print("\n".join(err.args)) else: - if(verbose) and verbose_lvl >= 2: print("Did not submit!") - if (verbose) and verbose_lvl >= 2: print("\n") - if (verbose) and verbose_lvl >= 2: print("job_postprocess ") + if (verbose) and verbose_lvl >= 2: + print("Did not submit!") + if (verbose) and verbose_lvl >= 2: + print("\n") + if (verbose) and verbose_lvl >= 2: + print("job_postprocess ") prefix_command = "" - #Resulting cnf is provided to use it in further approaches. + # Resulting cnf is provided to use it in further approaches. simSystem.cnf = Cnf(tmp_out_cnf, _future_file=True) - if (ana_id is not None) : previous_job_ID = ana_id - + if ana_id is not None: + previous_job_ID = ana_id + return previous_job_ID, tmp_jobname, simSystem diff --git a/pygromos/simulations/hpc_queuing/job_scheduling/schedulers/simulation_scheduler.py b/pygromos/simulations/hpc_queuing/job_scheduling/schedulers/simulation_scheduler.py index a217db0f..e2d3b3d3 100644 --- a/pygromos/simulations/hpc_queuing/job_scheduling/schedulers/simulation_scheduler.py +++ b/pygromos/simulations/hpc_queuing/job_scheduling/schedulers/simulation_scheduler.py @@ -8,7 +8,9 @@ from pygromos.files.gromos_system import Gromos_System from pygromos.simulations.hpc_queuing.job_scheduling.schedulers.scheduler_functions import chain_submission -from pygromos.simulations.hpc_queuing.job_scheduling.workers.simulation_workers import simulation_run_worker as workerScript +from pygromos.simulations.hpc_queuing.job_scheduling.workers.simulation_workers import ( + simulation_run_worker as workerScript, +) from pygromos.simulations.hpc_queuing.submission_systems._submission_system import _SubmissionSystem from pygromos.simulations.hpc_queuing.submission_systems.submission_job import Submission_job from pygromos.simulations.hpc_queuing.submission_systems.lsf import LSF @@ -16,16 +18,22 @@ spacer = utils.spacer -def do(in_simSystem: Gromos_System, - out_dir_path: str, - simulation_run_num: int, - equilibration_run_num: int = 0, - work_dir: str = None, - initialize_first_run= False, reinitialize_every_run= False, - analysis_script_path: str = None, - submission_system:_SubmissionSystem = LSF(), - previous_job_ID: int = None, no_double_submit:bool=False, - verbose: bool = True, verbose_lvl:int=1): + +def do( + in_simSystem: Gromos_System, + out_dir_path: str, + simulation_run_num: int, + equilibration_run_num: int = 0, + work_dir: str = None, + initialize_first_run=False, + reinitialize_every_run=False, + analysis_script_path: str = None, + submission_system: _SubmissionSystem = LSF(), + previous_job_ID: int = None, + no_double_submit: bool = False, + verbose: bool = True, + verbose_lvl: int = 1, +): """ Parameters @@ -54,21 +62,25 @@ def do(in_simSystem: Gromos_System, # prepare try: - if (verbose): print("Script: ", __file__) + if verbose: + print("Script: ", __file__) - if (verbose and verbose_lvl > 2): print(spacer+"Simulation PREPERATION\n"+spacer+"\n") + if verbose and verbose_lvl > 2: + print(spacer + "Simulation PREPERATION\n" + spacer + "\n") # Outdir bash.make_folder(out_dir_path) # final output_folder # workdir: - if (not isinstance(work_dir, type(None)) and work_dir != "None"): - if (verbose and verbose_lvl>2): print("\t -> Generating given workdir: " + work_dir) + if not isinstance(work_dir, type(None)) and work_dir != "None": + if verbose and verbose_lvl > 2: + print("\t -> Generating given workdir: " + work_dir) bash.make_folder(work_dir, "-p") os.chdir(work_dir) prepared_imd = work_dir + "/" + os.path.basename(in_simSystem.imd.path) else: - if (verbose and verbose_lvl>2): print("\t -> Using on node workdir") + if verbose and verbose_lvl > 2: + print("\t -> Using on node workdir") prepared_imd = out_dir_path + "/" + os.path.basename(in_simSystem.imd.path) # sim vars logs @@ -77,29 +89,32 @@ def do(in_simSystem: Gromos_System, # CHECK PATH DEPENDENCIES - all Files present? ##needed variables - check_path_dependencies_paths = [slave_script, out_dir_path] # Coord file is used by repex in_imd_path prepared_im + check_path_dependencies_paths = [ + slave_script, + out_dir_path, + ] # Coord file is used by repex in_imd_path prepared_im ##variable paths - if (not work_dir is None): + if not work_dir is None: check_path_dependencies_paths.append(work_dir) - if(not in_simSystem.top._future_file): + if not in_simSystem.top._future_file: check_path_dependencies_paths.append(in_simSystem.top.path) - if (not in_simSystem.cnf._future_file): + if not in_simSystem.cnf._future_file: check_path_dependencies_paths.append(in_simSystem.cnf.path) - if (not in_simSystem.imd._future_file): + if not in_simSystem.imd._future_file: check_path_dependencies_paths.append(in_simSystem.imd.path) - if (not in_simSystem.ptp is None): + if not in_simSystem.ptp is None: check_path_dependencies_paths.append(in_simSystem.ptp.path) - if (not in_simSystem.disres is None): + if not in_simSystem.disres is None: check_path_dependencies_paths.append(in_simSystem.disres.path) - if (not in_simSystem.posres is None): + if not in_simSystem.posres is None: check_path_dependencies_paths.append(in_simSystem.posres.path) - if (not in_simSystem.refpos is None): + if not in_simSystem.refpos is None: check_path_dependencies_paths.append(in_simSystem.refpos.path) - if (not in_simSystem.qmmm is None): + if not in_simSystem.qmmm is None: check_path_dependencies_paths.append(in_simSystem.qmmm.path) - #prepared_imd = bash.copy_file(in_simSystem.imd.path, prepared_imd) #Todo: Remove? @bschroed + # prepared_imd = bash.copy_file(in_simSystem.imd.path, prepared_imd) #Todo: Remove? @bschroed bash.check_path_dependencies(check_path_dependencies_paths, verbose=job_verb) @@ -115,56 +130,81 @@ def do(in_simSystem: Gromos_System, # RUN Job try: - if(verbose): print("\n"+spacer+"Simulation Setup:\n"+spacer) - if (verbose): print("steps_per_run: ", in_simSystem.imd.STEP.NSTLIM) - if (verbose): print("equis: ", equilibration_run_num) - if (verbose): print("simulation runs: ", simulation_run_num) + if verbose: + print("\n" + spacer + "Simulation Setup:\n" + spacer) + if verbose: + print("steps_per_run: ", in_simSystem.imd.STEP.NSTLIM) + if verbose: + print("equis: ", equilibration_run_num) + if verbose: + print("simulation runs: ", simulation_run_num) - #Submission + # Submission ## EQ - eq_job_id=None - if(equilibration_run_num>0): #EQUILIBRATION + eq_job_id = None + if equilibration_run_num > 0: # EQUILIBRATION tmp_outprefix = "eq_" + out_prefix tmp_jobname = in_simSystem.name + "_eq" - eq_job_id, tmp_jobname, in_simSystem = chain_submission(simSystem=in_simSystem, - out_dir_path= out_dir_path, out_prefix=tmp_outprefix, - jobname=tmp_jobname, - chain_job_repetitions=equilibration_run_num, worker_script=workerScript.__file__, - job_submission_system=submission_system, start_run_index = 1, - prefix_command = "", previous_job_ID = previous_job_ID, work_dir = work_dir, - initialize_first_run = initialize_first_run, reinitialize_every_run = reinitialize_every_run, - verbose = job_verb) + eq_job_id, tmp_jobname, in_simSystem = chain_submission( + simSystem=in_simSystem, + out_dir_path=out_dir_path, + out_prefix=tmp_outprefix, + jobname=tmp_jobname, + chain_job_repetitions=equilibration_run_num, + worker_script=workerScript.__file__, + job_submission_system=submission_system, + start_run_index=1, + prefix_command="", + previous_job_ID=previous_job_ID, + work_dir=work_dir, + initialize_first_run=initialize_first_run, + reinitialize_every_run=reinitialize_every_run, + verbose=job_verb, + ) ## MD tmp_outprefix = out_prefix tmp_jobname = in_simSystem.name - previous_job_ID = previous_job_ID if(eq_job_id is None) else eq_job_id - previous_job_ID, tmp_jobname, in_simSystem = chain_submission(simSystem=in_simSystem, - out_dir_path= out_dir_path, out_prefix=tmp_outprefix, - jobname=tmp_jobname, - chain_job_repetitions=equilibration_run_num + simulation_run_num, start_run_index = equilibration_run_num+1, - worker_script=workerScript.__file__, - job_submission_system=submission_system, - prefix_command = "", previous_job_ID = previous_job_ID, work_dir = None, - initialize_first_run= initialize_first_run, reinitialize_every_run= reinitialize_every_run, - verbose = job_verb) + previous_job_ID = previous_job_ID if (eq_job_id is None) else eq_job_id + previous_job_ID, tmp_jobname, in_simSystem = chain_submission( + simSystem=in_simSystem, + out_dir_path=out_dir_path, + out_prefix=tmp_outprefix, + jobname=tmp_jobname, + chain_job_repetitions=equilibration_run_num + simulation_run_num, + start_run_index=equilibration_run_num + 1, + worker_script=workerScript.__file__, + job_submission_system=submission_system, + prefix_command="", + previous_job_ID=previous_job_ID, + work_dir=None, + initialize_first_run=initialize_first_run, + reinitialize_every_run=reinitialize_every_run, + verbose=job_verb, + ) ana_previous_job_ID = previous_job_ID - if (not analysis_script_path is None): + if not analysis_script_path is None: tmp_jobname = in_simSystem.name + "_ana" ana_log = os.path.dirname(analysis_script_path) + "/ana_out.log" - if (verbose): print(spacer + "\n submit final analysis part \n") - if (verbose): print(ana_log) - if (verbose): print(analysis_script_path) - - sub_job = Submission_job(command="python3 "+analysis_script_path, - jobName=tmp_jobname, - outLog=ana_log, - queue_after_jobID=previous_job_ID) + if verbose: + print(spacer + "\n submit final analysis part \n") + if verbose: + print(ana_log) + if verbose: + print(analysis_script_path) + + sub_job = Submission_job( + command="python3 " + analysis_script_path, + jobName=tmp_jobname, + outLog=ana_log, + queue_after_jobID=previous_job_ID, + ) ana_previous_job_ID = submission_system.submit_to_queue(sub_job) - if (verbose): print("ANA jobID: " + str(previous_job_ID)) + if verbose: + print("ANA jobID: " + str(previous_job_ID)) except Exception as err: print("#####################################################################################") @@ -174,6 +214,5 @@ def do(in_simSystem: Gromos_System, traceback.print_exception(*sys.exc_info()) raise IOError("ERROR in SUBMISSION!") from err - #in_simSystem._future_promise = False #reset future promising if necessary + # in_simSystem._future_promise = False #reset future promising if necessary return ana_previous_job_ID - diff --git a/pygromos/simulations/hpc_queuing/job_scheduling/workers/analysis_workers/simulation_analysis.py b/pygromos/simulations/hpc_queuing/job_scheduling/workers/analysis_workers/simulation_analysis.py index ef92e668..7fa0fc8c 100644 --- a/pygromos/simulations/hpc_queuing/job_scheduling/workers/analysis_workers/simulation_analysis.py +++ b/pygromos/simulations/hpc_queuing/job_scheduling/workers/analysis_workers/simulation_analysis.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import os, sys -package_path = os.path.abspath(__file__+"/../../../../../..") + +package_path = os.path.abspath(__file__ + "/../../../../../..") # print(package_path) sys.path.append(package_path) @@ -11,33 +12,37 @@ from collections import OrderedDict from pygromos.gromos import gromosPP from pygromos.files.coord import cnf -from pygromos.files.trajectory import trc,tre, trg +from pygromos.files.trajectory import trc, tre, trg from pygromos.utils import bash -template_control_dict = OrderedDict({ - "concat": {"do": True, - "sub": { - "cp_cnf": True, - "repair_NaN": True, - "cp_omd": True, - "cat_trc": True, - "cat_tre": True, - "cat_trg": False, - "convert_trcs": False, - } - }, - "simulation_folder":{ - "do":True, - "sub":{ - "tar":True, - "remove":False - } +template_control_dict = OrderedDict( + { + "concat": { + "do": True, + "sub": { + "cp_cnf": True, + "repair_NaN": True, + "cp_omd": True, + "cat_trc": True, + "cat_tre": True, + "cat_trg": False, + "convert_trcs": False, + }, + }, + "simulation_folder": {"do": True, "sub": {"tar": True, "remove": False}}, } -}) - - -def do(in_simulation_dir:str, out_analysis_dir:str, sim_prefix:str, #in_system:Gromos_System, - gromosPP_bin_dir:str=None, n_processes: int = 1, control_dict: dict = None, verbose: bool = True): +) + + +def do( + in_simulation_dir: str, + out_analysis_dir: str, + sim_prefix: str, # in_system:Gromos_System, + gromosPP_bin_dir: str = None, + n_processes: int = 1, + control_dict: dict = None, + verbose: bool = True, +): """ Parameters @@ -58,141 +63,164 @@ def do(in_simulation_dir:str, out_analysis_dir:str, sim_prefix:str, #in_system:G gromos = gromosPP.GromosPP(gromosPP_bin_dir) - if (not os.path.exists(out_analysis_dir) and not os.path.isdir(out_analysis_dir)): + if not os.path.exists(out_analysis_dir) and not os.path.isdir(out_analysis_dir): bash.make_folder(out_analysis_dir) - if (not isinstance(control_dict, dict)): - warnings.warn("Recieved a non dict control-dict! Using the template. \n\tGot:"+str(control_dict)) + if not isinstance(control_dict, dict): + warnings.warn("Recieved a non dict control-dict! Using the template. \n\tGot:" + str(control_dict)) control_dict = template_control_dict # ORGANIZE FILES out_data_dir = out_analysis_dir + "/data" - if (not os.path.isdir(out_data_dir)): + if not os.path.isdir(out_data_dir): os.mkdir(out_data_dir) - if(control_dict["concat"]["do"]): - project_concatenation(in_folder=in_simulation_dir, in_prefix = sim_prefix, out_folder=out_data_dir, control_dict=control_dict["concat"]["sub"], verbose=verbose) - #in_simSystem=in_system, - #Other Analysis parts - + if control_dict["concat"]["do"]: + project_concatenation( + in_folder=in_simulation_dir, + in_prefix=sim_prefix, + out_folder=out_data_dir, + control_dict=control_dict["concat"]["sub"], + verbose=verbose, + ) + # in_simSystem=in_system, + # Other Analysis parts print(control_dict) - if(control_dict["simulation_folder"]["do"]): + if control_dict["simulation_folder"]["do"]: sub_dict = control_dict["simulation_folder"]["sub"] - if(os.path.exists(in_simulation_dir)): - if(sub_dict["tar"]): + if os.path.exists(in_simulation_dir): + if sub_dict["tar"]: out_tar_dir = bash.compress_tar(in_path=in_simulation_dir) - bash.remove_file(in_simulation_dir,additional_options="-r") + bash.remove_file(in_simulation_dir, additional_options="-r") - if(sub_dict["remove"]): - bash.remove_file(in_simulation_dir,additional_options="-r") + if sub_dict["remove"]: + bash.remove_file(in_simulation_dir, additional_options="-r") else: - warnings.warn("Simulation dir was not present. Skipped Compression.\nGiven Path: "+in_simulation_dir) + warnings.warn("Simulation dir was not present. Skipped Compression.\nGiven Path: " + in_simulation_dir) return 0 - -def project_concatenation(in_folder: str, out_folder: str, in_prefix:str, #in_simSystem: Gromos_System, - control_dict: Dict[str, bool], verbose: bool = False) -> dict: - #in_simSystem.work_folder = out_folder - out_prefix = out_folder+"/"+in_prefix #in_simSystem.name - if (control_dict["cp_cnf"]): - - out_cnf = out_prefix+".cnf" - if(os.path.exists(out_prefix+".cnf")): - warnings.warn("Skipping concatenation of tres, as there already exists one!\n " - "If you want to generate a new trc. Please delete the old one!\n\t Path:"+out_prefix+".cnf") +def project_concatenation( + in_folder: str, + out_folder: str, + in_prefix: str, # in_simSystem: Gromos_System, + control_dict: Dict[str, bool], + verbose: bool = False, +) -> dict: + # in_simSystem.work_folder = out_folder + out_prefix = out_folder + "/" + in_prefix # in_simSystem.name + if control_dict["cp_cnf"]: + + out_cnf = out_prefix + ".cnf" + if os.path.exists(out_prefix + ".cnf"): + warnings.warn( + "Skipping concatenation of tres, as there already exists one!\n " + "If you want to generate a new trc. Please delete the old one!\n\t Path:" + out_prefix + ".cnf" + ) else: - if (verbose): print("\tStart cnfs") + if verbose: + print("\tStart cnfs") # find all cnf files in this project - sim_dir_cnfs = gather_simulation_step_file_paths(in_folder, filePrefix=in_prefix, #in_simSystem.name, - fileSuffixes=".cnf", - verbose=verbose) + sim_dir_cnfs = gather_simulation_step_file_paths( + in_folder, filePrefix=in_prefix, fileSuffixes=".cnf", verbose=verbose # in_simSystem.name, + ) import glob - print(in_folder+"/"+in_prefix+"/*.cnf") - cnf_path = glob.glob(in_folder+"/"+in_prefix+"*/*.cnf")[-1] + + print(in_folder + "/" + in_prefix + "/*.cnf") + cnf_path = glob.glob(in_folder + "/" + in_prefix + "*/*.cnf")[-1] sim_cnf = cnf.Cnf(cnf_path) - if (control_dict["repair_NaN"]): - if(any([math.isnan(x) for x in sim_cnf.GENBOX.euler])): + if control_dict["repair_NaN"]: + if any([math.isnan(x) for x in sim_cnf.GENBOX.euler]): sim_cnf.GENBOX.euler = [0.0, 0.0, 0.0] - out_cnf = sim_cnf.write( out_prefix+".cnf") + out_cnf = sim_cnf.write(out_prefix + ".cnf") - #in_simSystem.cnf = sim_dir_cnfs[-1] - #in_simSystem.cnf.path = out_prefix+".cnf" - #in_simSystem.write_files(cnf=True, all=False) + # in_simSystem.cnf = sim_dir_cnfs[-1] + # in_simSystem.cnf.path = out_prefix+".cnf" + # in_simSystem.write_files(cnf=True, all=False) - if (control_dict["cp_omd"]): + if control_dict["cp_omd"]: - out_omd = out_prefix+".omd" - if(os.path.exists(out_prefix+".omd")): - warnings.warn("Skipping concatenation of tres, as there already exists one!\n " - "If you want to generate a new trc. Please delete the old one!\n\t Path:"+out_prefix+".omd") + out_omd = out_prefix + ".omd" + if os.path.exists(out_prefix + ".omd"): + warnings.warn( + "Skipping concatenation of tres, as there already exists one!\n " + "If you want to generate a new trc. Please delete the old one!\n\t Path:" + out_prefix + ".omd" + ) else: - if (verbose): print("\tStart omd") + if verbose: + print("\tStart omd") # find all omd files in this project - sim_dir_omd = gather_simulation_step_file_paths(in_folder, filePrefix=in_prefix, #in_simSystem.name, - fileSuffixes=".omd", - verbose=verbose) + sim_dir_omd = gather_simulation_step_file_paths( + in_folder, filePrefix=in_prefix, fileSuffixes=".omd", verbose=verbose # in_simSystem.name, + ) for omd in sim_dir_omd: shutil.copy2(omd, out_prefix + omd.split("/")[-1]) - - if (control_dict["cat_trc"]): + if control_dict["cat_trc"]: # find all trc files in this project - out_traj_path = out_prefix+".trc.h5" - if(os.path.exists(out_traj_path)): - warnings.warn("Skipping concatenation of trcs, as there already exists one!\n " - "If you want to generate a new trc. Please delete the old one!\n\t Path:"+out_traj_path) + out_traj_path = out_prefix + ".trc.h5" + if os.path.exists(out_traj_path): + warnings.warn( + "Skipping concatenation of trcs, as there already exists one!\n " + "If you want to generate a new trc. Please delete the old one!\n\t Path:" + out_traj_path + ) else: - if (verbose): print("\tStart Trc Cat") - traj_files = gather_simulation_step_file_paths(in_folder, filePrefix=in_prefix, - fileSuffixes=[".trc", ".trc.gz", ".trc.tar.gz"], - verbose=verbose) - if(len(traj_files) > 0): + if verbose: + print("\tStart Trc Cat") + traj_files = gather_simulation_step_file_paths( + in_folder, filePrefix=in_prefix, fileSuffixes=[".trc", ".trc.gz", ".trc.tar.gz"], verbose=verbose + ) + if len(traj_files) > 0: out_trc_file = trc.Trc(traj_files[0], auto_save=False) - if(len(traj_files)>0): + if len(traj_files) > 0: for tmp_trc_file in traj_files[1:]: tmp_trc = trc.Trc(tmp_trc_file, auto_save=False) out_trc_file += tmp_trc out_trc_file.write(output_path=out_traj_path) - if (control_dict["cat_tre"]): - out_traj_path = out_prefix+".tre.h5" - if(os.path.exists(out_traj_path)): - warnings.warn("Skipping concatenation of tres, as there already exists one!\n " - "If you want to generate a new trc. Please delete the old one!\n\t Path:"+out_traj_path) + if control_dict["cat_tre"]: + out_traj_path = out_prefix + ".tre.h5" + if os.path.exists(out_traj_path): + warnings.warn( + "Skipping concatenation of tres, as there already exists one!\n " + "If you want to generate a new trc. Please delete the old one!\n\t Path:" + out_traj_path + ) else: - if (verbose): print("\tStart Tre Cat") - traj_files = gather_simulation_step_file_paths(in_folder, filePrefix=in_prefix, - fileSuffixes=[".tre", ".tre.gz", ".tre.tar.gz"], - verbose=verbose) - if(len(traj_files) > 0): + if verbose: + print("\tStart Tre Cat") + traj_files = gather_simulation_step_file_paths( + in_folder, filePrefix=in_prefix, fileSuffixes=[".tre", ".tre.gz", ".tre.tar.gz"], verbose=verbose + ) + if len(traj_files) > 0: out_trc_file = tre.Tre(traj_files[0], auto_save=False) - if(len(traj_files)>0): + if len(traj_files) > 0: for tmp_trc_file in traj_files[1:]: tmp_trc = tre.Tre(tmp_trc_file, auto_save=False) out_trc_file += tmp_trc out_trc_file.write(output_path=out_traj_path) - if (control_dict["cat_trg"]): - out_traj_path = out_prefix+".trg.h5" - if(os.path.exists(out_traj_path)): - warnings.warn("Skipping concatenation of tres, as there already exists one!\n " - "If you want to generate a new trc. Please delete the old one!\n\t Path:"+out_traj_path) + if control_dict["cat_trg"]: + out_traj_path = out_prefix + ".trg.h5" + if os.path.exists(out_traj_path): + warnings.warn( + "Skipping concatenation of tres, as there already exists one!\n " + "If you want to generate a new trc. Please delete the old one!\n\t Path:" + out_traj_path + ) else: - if (verbose): print("\tStart Tre Cat") - traj_files = gather_simulation_step_file_paths(in_folder, filePrefix=in_prefix, - fileSuffixes=[".trg", ".trg.gz", ".trg.tar.gz"], - verbose=verbose) - if(len(traj_files) > 0): + if verbose: + print("\tStart Tre Cat") + traj_files = gather_simulation_step_file_paths( + in_folder, filePrefix=in_prefix, fileSuffixes=[".trg", ".trg.gz", ".trg.tar.gz"], verbose=verbose + ) + if len(traj_files) > 0: out_trg_file = trg.Trg(traj_files[0], auto_save=False) - if(len(traj_files)>0): + if len(traj_files) > 0: for tmp_trg_file in traj_files[1:]: tmp_trg = trg.Trg(tmp_trg_file, auto_save=False) out_trg_file += tmp_trg out_trg_file.write(output_path=out_traj_path) - """ if (control_dict["convert_trcs"]): @@ -221,13 +249,18 @@ def project_concatenation(in_folder: str, out_folder: str, in_prefix:str, #in_si verbose=verbose, boundary_conditions=boundary_conditions) """ - if (verbose): print("all jobs finished") - return out_cnf # in_simSystem - - -def gather_simulation_step_file_paths(in_folder: str, filePrefix: str = "", - fileSuffixes: Union[str, List[str]] = [".tre", ".tre.tar.gz"], - verbose: bool = False, finalNumberingSort=False) -> Dict[int, List[str]]: + if verbose: + print("all jobs finished") + return out_cnf # in_simSystem + + +def gather_simulation_step_file_paths( + in_folder: str, + filePrefix: str = "", + fileSuffixes: Union[str, List[str]] = [".tre", ".tre.tar.gz"], + verbose: bool = False, + finalNumberingSort=False, +) -> Dict[int, List[str]]: """gather_replica_file_paths Finds all trajectory paths in a simulation folder. @@ -251,32 +284,45 @@ def gather_simulation_step_file_paths(in_folder: str, filePrefix: str = "", """ - if (isinstance(fileSuffixes, str)): + if isinstance(fileSuffixes, str): fileSuffixes = [fileSuffixes] # browse folders ##init statewise dic files = [] - if (verbose): print("SEARCH PATTERN: " + filePrefix + " + * +" + str(fileSuffixes)) + if verbose: + print("SEARCH PATTERN: " + filePrefix + " + * +" + str(fileSuffixes)) for dirname, dirnames, filenames in os.walk(in_folder): - if (str(dirname[-1]).isdigit() and os.path.basename(dirname).startswith("eq")): + if str(dirname[-1]).isdigit() and os.path.basename(dirname).startswith("eq"): continue # check actual in_dir for file pattern - tmp_files = [file for file in filenames if - (filePrefix in file and any([file.endswith(suffix) for suffix in fileSuffixes]))] + tmp_files = [ + file + for file in filenames + if (filePrefix in file and any([file.endswith(suffix) for suffix in fileSuffixes])) + ] if len(tmp_files) != 0: grom_file_prefix = sorted( - [dirname + "/" + file for file in tmp_files if (any([suffix in file for suffix in fileSuffixes]))]) + [dirname + "/" + file for file in tmp_files if (any([suffix in file for suffix in fileSuffixes]))] + ) files += grom_file_prefix - if verbose: print("walking to in_dir: ", os.path.basename(dirname), "found: ", len(tmp_files)) + if verbose: + print("walking to in_dir: ", os.path.basename(dirname), "found: ", len(tmp_files)) files = sorted(files, key=lambda x: int(x.split("_")[-1].split(".")[0])) - if (verbose): + if verbose: print("\nfoundFiles:\n") print("\t" + "\t".join([y + "\n" for y in files])) - if (len(files) == 0): - warnings.warn("could not find any file with the prefix: " + str(filePrefix) + " * "+str(fileSuffixes)+" in folder : \n" + in_folder) + if len(files) == 0: + warnings.warn( + "could not find any file with the prefix: " + + str(filePrefix) + + " * " + + str(fileSuffixes) + + " in folder : \n" + + in_folder + ) return files diff --git a/pygromos/simulations/hpc_queuing/job_scheduling/workers/simulation_workers/clean_up_simulation_files.py b/pygromos/simulations/hpc_queuing/job_scheduling/workers/simulation_workers/clean_up_simulation_files.py index 327327c4..838607b3 100644 --- a/pygromos/simulations/hpc_queuing/job_scheduling/workers/simulation_workers/clean_up_simulation_files.py +++ b/pygromos/simulations/hpc_queuing/job_scheduling/workers/simulation_workers/clean_up_simulation_files.py @@ -9,7 +9,8 @@ import argparse import glob import os, sys -package_path = os.path.abspath(__file__+"/../../../../../..") + +package_path = os.path.abspath(__file__ + "/../../../../../..") # print(package_path) sys.path.append(package_path) @@ -33,20 +34,25 @@ def do(in_simulation_dir: str, n_processes: int = 1, verbose: bool = True) -> No None """ import time + time.sleep(time_wait_s_for_filesystem) # compress files: - if (verbose): print("Search Files START", "\n") + if verbose: + print("Search Files START", "\n") trx_files = glob.glob(in_simulation_dir + "/*.tr?") - if (verbose): print("Found tr?s: ", trx_files, "\n") + if verbose: + print("Found tr?s: ", trx_files, "\n") - if (len(trx_files) == 0): + if len(trx_files) == 0: exit(0) else: - if (verbose): print("COMPRESS START\n") + if verbose: + print("COMPRESS START\n") fM.compress_files(trx_files, n_processes=n_processes) - if (verbose): print("COMPRESS DONE\n") + if verbose: + print("COMPRESS DONE\n") # do more? @@ -54,14 +60,16 @@ def do(in_simulation_dir: str, n_processes: int = 1, verbose: bool = True) -> No if __name__ == "__main__": # INPUT JUGGELING parser = argparse.ArgumentParser(description="Run Gromos after simulation cleanup\n\n" + str(__doc__)) - parser.add_argument('-in_simulation_dir', type=str, required=True, - help="give the simulation directory path of a gromos simulation.") - parser.add_argument('-n_processes', type=int, required=False, default=1, - help="give the number of process for parallelisation.") + parser.add_argument( + "-in_simulation_dir", type=str, required=True, help="give the simulation directory path of a gromos simulation." + ) + parser.add_argument( + "-n_processes", type=int, required=False, default=1, help="give the number of process for parallelisation." + ) args, unkown_args = parser.parse_known_args() - if (len(unkown_args) > 0): + if len(unkown_args) > 0: print("ERROR FOUND UNKNOWN ARG") parser.print_help() raise IOError("Parser does not know following arguments:\n\t" + "\n\t".join(unkown_args)) diff --git a/pygromos/simulations/hpc_queuing/job_scheduling/workers/simulation_workers/simulation_run_worker.py b/pygromos/simulations/hpc_queuing/job_scheduling/workers/simulation_workers/simulation_run_worker.py index 973200aa..01e40db7 100644 --- a/pygromos/simulations/hpc_queuing/job_scheduling/workers/simulation_workers/simulation_run_worker.py +++ b/pygromos/simulations/hpc_queuing/job_scheduling/workers/simulation_workers/simulation_run_worker.py @@ -4,7 +4,7 @@ import time import math -package_path = os.path.abspath(__file__+"/../../../../../..") +package_path = os.path.abspath(__file__ + "/../../../../../..") sys.path.append(package_path) from pygromos.gromos import gromosXX as mdGromosXX @@ -16,13 +16,33 @@ import pygromos.simulations.hpc_queuing.job_scheduling.workers.simulation_workers.clean_up_simulation_files as zip_files -def work(out_dir : str, in_cnf_path : str, in_imd_path : str, in_top_path : str, runID:int=1, - in_perttopo_path: str = None, in_disres_path: str= None, in_posres_path:str = None, in_refpos_path:str=None, - in_qmmm_path:str=None, out_trc:bool=False, out_tre: bool=False, - out_trg: bool = False, out_trv: bool = False, out_trf: bool = False, out_trs: bool = False, - nmpi: int = 1, nomp: int = 1, - reinitialize_every_run: bool = False, initialize_first_run:bool = True, - gromosXX_bin_dir: str = None, work_dir: str = None, zip_trajectories: bool = True, **kwargs): + +def work( + out_dir: str, + in_cnf_path: str, + in_imd_path: str, + in_top_path: str, + runID: int = 1, + in_perttopo_path: str = None, + in_disres_path: str = None, + in_posres_path: str = None, + in_refpos_path: str = None, + in_qmmm_path: str = None, + out_trc: bool = False, + out_tre: bool = False, + out_trg: bool = False, + out_trv: bool = False, + out_trf: bool = False, + out_trs: bool = False, + nmpi: int = 1, + nomp: int = 1, + reinitialize_every_run: bool = False, + initialize_first_run: bool = True, + gromosXX_bin_dir: str = None, + work_dir: str = None, + zip_trajectories: bool = True, + **kwargs +): """ Executed by repex_EDS_long_production_run as workers @@ -75,24 +95,26 @@ def work(out_dir : str, in_cnf_path : str, in_imd_path : str, in_top_path : str, else: print("Could not find TMPDIR!\n Switched to outdir for work") work_dir = out_dir - if (not os.path.isdir(work_dir)): bash.make_folder(work_dir) + if not os.path.isdir(work_dir): + bash.make_folder(work_dir) print("workDIR: " + str(work_dir)) - + # Check if the calculation is running on multiple nodes: - if 'LSB_HOSTS' in os.environ: - hosts = os.environ['LSB_HOSTS'].split() + if "LSB_HOSTS" in os.environ: + hosts = os.environ["LSB_HOSTS"].split() else: hosts = [] multi_node = True if len(hosts) > 1 else False - + # run a euler script to create tmpdir on all nodes - if multi_node: os.system('remote_tmpdir create') - + if multi_node: + os.system("remote_tmpdir create") + os.chdir(work_dir) - - #Prepare IMD file: + + # Prepare IMD file: tmp_prefix = os.path.basename(out_dir) - tmp_imd_path = out_dir+"/"+tmp_prefix+".imd" + tmp_imd_path = out_dir + "/" + tmp_prefix + ".imd" imd_file = imd.Imd(in_imd_path) cnf_file = cnf.Cnf(in_cnf_path) @@ -102,48 +124,47 @@ def work(out_dir : str, in_cnf_path : str, in_imd_path : str, in_top_path : str, is_vacuum = False is_energymin_sim = False - if(imd_file.BOUNDCOND.NTB == 0): + if imd_file.BOUNDCOND.NTB == 0: is_vacuum = True - if (hasattr(imd_file, 'STOCHDYN')): - if (imd_file.STOCHDYN.NTSD): + if hasattr(imd_file, "STOCHDYN"): + if imd_file.STOCHDYN.NTSD: is_stochastic_dynamics_sim = True - if(hasattr(imd_file, "ENERGYMIN")): - if (imd_file.ENERGYMIN.NTEM > 0): + if hasattr(imd_file, "ENERGYMIN"): + if imd_file.ENERGYMIN.NTEM > 0: is_energymin_sim = True - - #Adapt Initializations: - if (reinitialize_every_run or (initialize_first_run and runID == 1)): + + # Adapt Initializations: + if reinitialize_every_run or (initialize_first_run and runID == 1): imd_file.INITIALISE.NTIVEL = 1 - if(hasattr(imd_file, "CONSTRAINT")): - imd_file.INITIALISE.NTISHK = 0 if(imd_file.CONSTRAINT.NTC > 0) else 1 - - if(hasattr(imd_file, "MULTIBATH")): - imd_file.INITIALISE.NTINHT = 0 if(imd_file.MULTIBATH.ALGORITHM <= 1) else 1 - - - imd_file.INITIALISE.NTISHI = 0 if(hasattr(cnf_file, "LATTICESHIFT")) else 1 + if hasattr(imd_file, "CONSTRAINT"): + imd_file.INITIALISE.NTISHK = 0 if (imd_file.CONSTRAINT.NTC > 0) else 1 + + if hasattr(imd_file, "MULTIBATH"): + imd_file.INITIALISE.NTINHT = 0 if (imd_file.MULTIBATH.ALGORITHM <= 1) else 1 + + imd_file.INITIALISE.NTISHI = 0 if (hasattr(cnf_file, "LATTICESHIFT")) else 1 imd_file.INITIALISE.NTIRTC = 0 imd_file.INITIALISE.NTICOM = 0 imd_file.INITIALISE.NTISTI = 0 - if (is_stochastic_dynamics_sim): + if is_stochastic_dynamics_sim: imd_file.INITIALISE.NTISTI = 1 - elif(initialize_first_run and runID > 1): + elif initialize_first_run and runID > 1: imd_file.INITIALISE.NTIVEL = 0 - imd_file.INITIALISE.NTISHI = 0 - imd_file.INITIALISE.NTISHK = 0 - imd_file.INITIALISE.NTINHT = 0 + imd_file.INITIALISE.NTISHI = 0 + imd_file.INITIALISE.NTISHK = 0 + imd_file.INITIALISE.NTINHT = 0 imd_file.INITIALISE.NTINHB = 0 imd_file.INITIALISE.NTIRTC = 0 imd_file.INITIALISE.NTICOM = 0 imd_file.INITIALISE.NTISTI = 0 - if (is_stochastic_dynamics_sim or is_vacuum): + if is_stochastic_dynamics_sim or is_vacuum: imd_file.INITIALISE.NTISHI = 1 ##Write out: @@ -154,19 +175,31 @@ def work(out_dir : str, in_cnf_path : str, in_imd_path : str, in_top_path : str, try: print(spacer + "\n start MD " + str(os.path.basename(tmp_imd_path)) + "\n") - #TODO: This is a stupid workaround as Euler tends to place nans in the euler angles, that should not be there! - if(hasattr(cnf_file, "GENBOX") and any([math.isnan(x) for x in cnf_file.GENBOX.euler])): + # TODO: This is a stupid workaround as Euler tends to place nans in the euler angles, that should not be there! + if hasattr(cnf_file, "GENBOX") and any([math.isnan(x) for x in cnf_file.GENBOX.euler]): cnf_file.GENBOX.euler = [0.0, 0.0, 0.0] cnf_file.write(in_cnf_path) try: - omd_file_path = gromosXX.md_run(in_topo_path=in_top_path, in_coord_path=in_cnf_path, in_imd_path=tmp_imd_path, - in_pert_topo_path=in_perttopo_path, in_disres_path=in_disres_path, - in_posresspec_path=in_posres_path, in_refpos_path=in_refpos_path, - in_qmmm_path=in_qmmm_path, nmpi=nmpi, nomp=nomp, - out_prefix=tmp_prefix, - out_tre=out_tre, out_trc=out_trc, - out_trg=out_trg, out_trs=out_trs, out_trf=out_trf, out_trv=out_trv, - verbose=True) + omd_file_path = gromosXX.md_run( + in_topo_path=in_top_path, + in_coord_path=in_cnf_path, + in_imd_path=tmp_imd_path, + in_pert_topo_path=in_perttopo_path, + in_disres_path=in_disres_path, + in_posresspec_path=in_posres_path, + in_refpos_path=in_refpos_path, + in_qmmm_path=in_qmmm_path, + nmpi=nmpi, + nomp=nomp, + out_prefix=tmp_prefix, + out_tre=out_tre, + out_trc=out_trc, + out_trg=out_trg, + out_trs=out_trs, + out_trf=out_trf, + out_trv=out_trv, + verbose=True, + ) print("Waiting to find: ", omd_file_path.replace(".omd", ".cnf")) bash.wait_for_fileSystem(omd_file_path.replace(".omd", ".cnf")) @@ -175,24 +208,24 @@ def work(out_dir : str, in_cnf_path : str, in_imd_path : str, in_top_path : str, except Exception as err: print("Failed! process returned: \n Err: \n" + "\n".join(err.args)) md_failed = True - + # zip the files after the simulation. n_cpu_zip = nmpi if nmpi >= nomp else nomp if not multi_node and zip_trajectories: - zip_files.do(in_simulation_dir=work_dir, n_processes=n_cpu_zip) + zip_files.do(in_simulation_dir=work_dir, n_processes=n_cpu_zip) # Copy the files back to the proper directory when calc occured on scratch - if (out_dir != work_dir): + if out_dir != work_dir: if not multi_node: bash.move_file(work_dir + "/*", out_dir) - else: + else: for host in hosts: - command = 'ssh ' + host + ' \"mv ${TMPDIR}/* ' + out_dir + '\"' + command = "ssh " + host + ' "mv ${TMPDIR}/* ' + out_dir + '"' os.system(command) - os.system('remote_tmpdir delete') # Works for both multi or single node - + os.system("remote_tmpdir delete") # Works for both multi or single node + # Note: If job is multi-node, it is simpler to zip things in out_dir after copying back - if multi_node and zip_trajectories: + if multi_node and zip_trajectories: zip_files.do(in_simulation_dir=out_dir, n_processes=n_cpu_zip) except Exception as err: @@ -200,11 +233,12 @@ def work(out_dir : str, in_cnf_path : str, in_imd_path : str, in_top_path : str, print(type(err), file=sys.stderr) print(err.args, file=sys.stderr) exit(1) - if(md_failed): - print("\nFailed during simulations: \n Checkout: \n "+str(tmp_prefix)+".omd", file=sys.stderr) + if md_failed: + print("\nFailed during simulations: \n Checkout: \n " + str(tmp_prefix) + ".omd", file=sys.stderr) exit(1) exit(0) + if __name__ == "__main__": # INPUT JUGGELING args = dynamic_parser(work, title="Run MD-Worker") diff --git a/pygromos/simulations/hpc_queuing/submission_systems/__init__.py b/pygromos/simulations/hpc_queuing/submission_systems/__init__.py index 213e43a8..927afa05 100644 --- a/pygromos/simulations/hpc_queuing/submission_systems/__init__.py +++ b/pygromos/simulations/hpc_queuing/submission_systems/__init__.py @@ -6,9 +6,9 @@ def get_submission_system(testing: bool = False): - if (testing): + if testing: return DUMMY - if ("eu" in socket.gethostname()): + if "eu" in socket.gethostname(): return LSF else: - return LOCAL \ No newline at end of file + return LOCAL diff --git a/pygromos/simulations/hpc_queuing/submission_systems/_submission_system.py b/pygromos/simulations/hpc_queuing/submission_systems/_submission_system.py index 1d6608ea..d2f70a38 100644 --- a/pygromos/simulations/hpc_queuing/submission_systems/_submission_system.py +++ b/pygromos/simulations/hpc_queuing/submission_systems/_submission_system.py @@ -3,6 +3,7 @@ from pygromos.simulations.hpc_queuing.submission_systems.submission_job import Submission_job + class _SubmissionSystem: verbose: bool submission: bool @@ -11,13 +12,24 @@ class _SubmissionSystem: _nmpi: int _nomp: int _max_storage: float - job_queue_list: pd.DataFrame #contains all jobs in the queue (from this users) + job_queue_list: pd.DataFrame # contains all jobs in the queue (from this users) _zip_trajectories: bool - def __init__(self, submission: bool = False, - nmpi: int = 1, nomp: int = 1, max_storage: float = 1000, job_duration: str = "24:00", - verbose: bool = False, enviroment=None, block_double_submission:bool=True, chain_prefix:str="done", - begin_mail:bool=False, end_mail:bool=False, zip_trajectories: bool = True): + def __init__( + self, + submission: bool = False, + nmpi: int = 1, + nomp: int = 1, + max_storage: float = 1000, + job_duration: str = "24:00", + verbose: bool = False, + enviroment=None, + block_double_submission: bool = True, + chain_prefix: str = "done", + begin_mail: bool = False, + end_mail: bool = False, + zip_trajectories: bool = True, + ): """ Construct a submission system with required parameters. @@ -40,7 +52,7 @@ def __init__(self, submission: bool = False, block_double_submission: bool, optional if a job with the same name is already in the queue, it will not be submitted again. (default: True) chain_prefix: str, optional - the mode with witch jobs are chained together (default: "done") + the mode with witch jobs are chained together (default: "done") (options: "done", "exit", "ended", "started", "post_done", "post_err") begin_mail: bool, optional determines if a mail is sent when job starts @@ -63,10 +75,10 @@ def __init__(self, submission: bool = False, self.end_mail = end_mail self._zip_trajectories = zip_trajectories - def submit_to_queue(self, sub_job:Submission_job) -> int: + def submit_to_queue(self, sub_job: Submission_job) -> int: return -1 - def submit_jobAarray_to_queue(self, sub_job:Submission_job) -> int: + def submit_jobAarray_to_queue(self, sub_job: Submission_job) -> int: return -1 def get_script_generation_command(self, var_name: str = None, var_prefixes: str = "") -> str: @@ -85,19 +97,33 @@ def get_script_generation_command(self, var_name: str = None, var_prefixes: str """ name = self.__class__.__name__ - if (var_name is None): + if var_name is None: var_name = var_prefixes + name gen_cmd = "#Generate " + name + "\n" gen_cmd += "from " + self.__module__ + " import " + name + " as " + name + "_obj" + "\n" - gen_cmd += var_name + " = " + name + "_obj(submission=" + str(self.submission) + ", verbose=" + str( - self.verbose) + ", nmpi="+str(self.nmpi)+", nomp="+str(self.nomp)+ ", job_duration=\""+str(self.job_duration)+"\")\n\n" + gen_cmd += ( + var_name + + " = " + + name + + "_obj(submission=" + + str(self.submission) + + ", verbose=" + + str(self.verbose) + + ", nmpi=" + + str(self.nmpi) + + ", nomp=" + + str(self.nomp) + + ', job_duration="' + + str(self.job_duration) + + '")\n\n' + ) return gen_cmd def get_jobs_from_queue(self, job_text: str, **kwargs) -> List[int]: return [] - def search_queue_for_jobname(self, job_name: str, regex:bool=False, **kwargs)->pd.DataFrame: + def search_queue_for_jobname(self, job_name: str, regex: bool = False, **kwargs) -> pd.DataFrame: """get_jobs_from_queue this function searches the job queue for a certain job id. @@ -113,10 +139,10 @@ def search_queue_for_jobname(self, job_name: str, regex:bool=False, **kwargs)->p NotImplementedError Needs to be implemented in subclasses """ - + raise NotImplementedError("Do is not implemented for: " + self.__class__.__name__) - def search_queue_for_jobid(self, job_id: int, **kwargs)->pd.DataFrame: + def search_queue_for_jobid(self, job_id: int, **kwargs) -> pd.DataFrame: """search_queue_for_jobid this jobs searches the job queue for a certain job id. @@ -133,7 +159,7 @@ def search_queue_for_jobid(self, job_id: int, **kwargs)->pd.DataFrame: raise NotImplementedError("search_queue_for_jobID is not implemented for: " + self.__class__.__name__) - def is_job_in_queue(self, job_name: str=None, job_id:int=None, _onlyRUNPEND:bool=True) -> bool: + def is_job_in_queue(self, job_name: str = None, job_id: int = None, _onlyRUNPEND: bool = True) -> bool: """ checks wether a function is still in the lsf queue @@ -151,24 +177,24 @@ def is_job_in_queue(self, job_name: str=None, job_id:int=None, _onlyRUNPEND:bool bool is the job in the lsf queue? """ - if(not job_name is None): - if(_onlyRUNPEND): + if not job_name is None: + if _onlyRUNPEND: queued_job_ids = self.search_queue_for_jobname(job_name=job_name) queued_job_ids = queued_job_ids.where(queued_job_ids.STAT.isin(["RUN", "PEND"])).dropna() return len(queued_job_ids) > 0 else: return len(self.search_queue_for_jobname(job_name=job_name)) > 0 - elif(not job_id is None): - if(_onlyRUNPEND): + elif not job_id is None: + if _onlyRUNPEND: queued_job_ids = self.search_queue_for_jobid(job_id=job_id) queued_job_ids = queued_job_ids.where(queued_job_ids.STAT.isin(["RUN", "PEND"])).dropna() return len(queued_job_ids) > 0 else: - return len(self.search_queue_for_jobid(job_id=job_id)) >0 + return len(self.search_queue_for_jobid(job_id=job_id)) > 0 else: raise ValueError("Please provide either the job_name or the job_id!") - def kill_jobs(self, job_name:str=None, regex:bool=False, job_ids: Union[List[int], int]=None): + def kill_jobs(self, job_name: str = None, regex: bool = False, job_ids: Union[List[int], int] = None): """ this function can be used to terminate or remove pending jobs from the queue. Parameters @@ -183,7 +209,6 @@ def kill_jobs(self, job_name:str=None, regex:bool=False, job_ids: Union[List[int """ raise NotImplementedError("kill_jobs is not implemented for: " + self.__class__.__name__) - @property def nmpi(self) -> int: return self._nmpi diff --git a/pygromos/simulations/hpc_queuing/submission_systems/dummy.py b/pygromos/simulations/hpc_queuing/submission_systems/dummy.py index c34a76e1..9e8e8766 100644 --- a/pygromos/simulations/hpc_queuing/submission_systems/dummy.py +++ b/pygromos/simulations/hpc_queuing/submission_systems/dummy.py @@ -8,15 +8,29 @@ class DUMMY(_SubmissionSystem): """DUMMY - This SubmissionSystem is for testing submission systems. It basically prints everything out. + This SubmissionSystem is for testing submission systems. It basically prints everything out. """ - def __init__(self, verbose: bool = False, nomp: int = 1, nmpi: int = 1, job_duration: str = "24:00", - submission: bool = True, enviroment=None): - time_wait_s_for_filesystem=0 - super().__init__(verbose=verbose, nmpi=nmpi, nomp=nomp, job_duration=job_duration, submission=submission, enviroment=enviroment) - - def submit_to_queue(self, sub_job:Submission_job) -> Union[int, None]: + def __init__( + self, + verbose: bool = False, + nomp: int = 1, + nmpi: int = 1, + job_duration: str = "24:00", + submission: bool = True, + enviroment=None, + ): + time_wait_s_for_filesystem = 0 + super().__init__( + verbose=verbose, + nmpi=nmpi, + nomp=nomp, + job_duration=job_duration, + submission=submission, + enviroment=enviroment, + ) + + def submit_to_queue(self, sub_job: Submission_job) -> Union[int, None]: """submit_to_queue This function submits a str command to the submission system. @@ -31,14 +45,14 @@ def submit_to_queue(self, sub_job:Submission_job) -> Union[int, None]: if a job was submitted the jobID is returned else None. """ - if (self.submission): + if self.submission: print("\n", sub_job.command, "\n") return 0 else: - print('did not submit') + print("did not submit") return None - def submit_jobAarray_to_queue(self, sub_job:Submission_job) -> Union[int, None]: + def submit_jobAarray_to_queue(self, sub_job: Submission_job) -> Union[int, None]: """submit_jobAarray_to_queue this function is submitting Parameters @@ -52,14 +66,14 @@ def submit_jobAarray_to_queue(self, sub_job:Submission_job) -> Union[int, None]: if a job was submitted the jobID is returned else None. """ - if (self.submission): + if self.submission: print() for jobID in range(sub_job.start_job, sub_job.end_job + 1): print("Job " + str(jobID) + ":", sub_job.command, "\n") print() return 0 else: - print('did not submit') + print("did not submit") return None def get_jobs_from_queue(self, job_text: str, **kwargs) -> List[int]: @@ -77,7 +91,8 @@ def get_jobs_from_queue(self, job_text: str, **kwargs) -> List[int]: List[int] output contains all ids of fitting jobs to the querry """ - if (self.verbose): print("Retrieving jobs from list with: ", job_text) + if self.verbose: + print("Retrieving jobs from list with: ", job_text) warnings.warn("Queue search was called, but no queue present!") return [] @@ -96,6 +111,7 @@ def search_queue_for_jobname(self, job_name: str, **kwargs) -> List[str]: List[str] the output of the queue containing the jobname """ - if (self.verbose): print("Searching job Name: ", job_name) + if self.verbose: + print("Searching job Name: ", job_name) warnings.warn("Queue search was called, but no queue present!") return [] diff --git a/pygromos/simulations/hpc_queuing/submission_systems/local.py b/pygromos/simulations/hpc_queuing/submission_systems/local.py index aaf81a3f..0ae0bc28 100644 --- a/pygromos/simulations/hpc_queuing/submission_systems/local.py +++ b/pygromos/simulations/hpc_queuing/submission_systems/local.py @@ -15,32 +15,48 @@ class LOCAL(_SubmissionSystem): This class handles local submission without a queueing system """ - def __init__(self, submission: bool = True, nomp: int = 1, nmpi: int = 1, job_duration: str = "24:00", - verbose: bool = False, enviroment=None, zip_trajectories: bool = True): - time_wait_s_for_filesystem=0 - super().__init__(verbose=verbose, nmpi=nmpi, nomp=nomp, job_duration=job_duration, submission=submission, enviroment=enviroment, zip_trajectories=zip_trajectories) - - def submit_to_queue(self, sub_job:Submission_job) -> int: + def __init__( + self, + submission: bool = True, + nomp: int = 1, + nmpi: int = 1, + job_duration: str = "24:00", + verbose: bool = False, + enviroment=None, + zip_trajectories: bool = True, + ): + time_wait_s_for_filesystem = 0 + super().__init__( + verbose=verbose, + nmpi=nmpi, + nomp=nomp, + job_duration=job_duration, + submission=submission, + enviroment=enviroment, + zip_trajectories=zip_trajectories, + ) + + def submit_to_queue(self, sub_job: Submission_job) -> int: """ submitt a local job """ - + orig_dir = os.getcwd() - if (isinstance(sub_job.submit_from_dir, str) and os.path.isdir(sub_job.submit_from_dir)): + if isinstance(sub_job.submit_from_dir, str) and os.path.isdir(sub_job.submit_from_dir): os.chdir(sub_job.submit_from_dir) command_file_path = sub_job.submit_from_dir + "/job_" + str(sub_job.jobName) + ".sh" else: command_file_path = "./job_" + str(sub_job.jobName) + ".sh" - sub_job.command = sub_job.command.strip() # remove trailing linebreaks + sub_job.command = sub_job.command.strip() # remove trailing linebreaks - if (self.nomp >= 1): + if self.nomp >= 1: command = "export OMP_NUM_THREADS=" + str(self.nomp) + ";\n " + sub_job.command + "" else: command = sub_job.command - if (sub_job.sumbit_from_file): + if sub_job.sumbit_from_file: command_file = open(command_file_path, "w") command_file.write("#!/bin/bash\n") command_file.write(command.replace("&& ", ";\n") + ";\n") @@ -50,16 +66,19 @@ def submit_to_queue(self, sub_job:Submission_job) -> int: ##finalize string - if (self.verbose): print("Submission Command: \t", " ".join(command)) - if (self.submission): + if self.verbose: + print("Submission Command: \t", " ".join(command)) + if self.submission: try: process = bash.execute(command=command, catch_STD=True, env=self._enviroment) std_out_buff = map(str, process.stdout.readlines()) std_out = "\t" + "\n\t".join(std_out_buff) # next sopt_job is queued with id: - if self.verbose: print("STDOUT: \n\t" + std_out + "\nEND\n") - if (os.path.exists(orig_dir)): os.chdir(orig_dir) + if self.verbose: + print("STDOUT: \n\t" + std_out + "\nEND\n") + if os.path.exists(orig_dir): + os.chdir(orig_dir) return 0 except: @@ -67,36 +86,38 @@ def submit_to_queue(self, sub_job:Submission_job) -> int: print(process) except: pass - raise ChildProcessError("command failed: \n" + - str(command)) + raise ChildProcessError("command failed: \n" + str(command)) else: print("Did not submit: ", command) return -1 - def submit_jobAarray_to_queue(self, sub_job:Submission_job) -> int: - """ + def submit_jobAarray_to_queue(self, sub_job: Submission_job) -> int: + """ submitt a local job array """ - # generate submission_string: submission_string = "" - if (isinstance(sub_job.submit_from_dir, str) and os.path.isdir(sub_job.submit_from_dir)): + if isinstance(sub_job.submit_from_dir, str) and os.path.isdir(sub_job.submit_from_dir): submission_string += "cd " + sub_job.submit_from_dir + " && " - if (self.nomp > 1): + if self.nomp > 1: command = submission_string + " export OMP_NUM_THREADS=" + str(self.nomp) + " && " + sub_job.command else: command = submission_string + sub_job.command - if (self.verbose): print("Submission Command: \t", " ".join(submission_string)) - if (self.submission): + if self.verbose: + print("Submission Command: \t", " ".join(submission_string)) + if self.submission: try: for jobID in range(sub_job.start_job, sub_job.end_job + 1): - std_out_buff = bash.execute(command="export JOBID=" + str(jobID) + " && " + command, env=self._enviroment) + std_out_buff = bash.execute( + command="export JOBID=" + str(jobID) + " && " + command, env=self._enviroment + ) std_out = "\n".join(std_out_buff.readlines()) - if self.verbose: print("sdtout : " + str(std_out)) + if self.verbose: + print("sdtout : " + str(std_out)) return 0 except: raise ChildProcessError("could not submit this command: \n" + submission_string) @@ -104,7 +125,6 @@ def submit_jobAarray_to_queue(self, sub_job:Submission_job) -> int: print("Did note submit: ", command) return -1 - def search_queue_for_jobname(self, job_name: str, **kwargs) -> List[str]: """search_queue_for_jobname @@ -121,13 +141,12 @@ def search_queue_for_jobname(self, job_name: str, **kwargs) -> List[str]: List[str] the output of the queue containing the jobname """ - if (self.verbose): + if self.verbose: print("Searching job Name: ", job_name) warnings.warn("Queue search was called, but no queue present!") return [] - - def search_queue_for_jobid(self, job_id: int, **kwargs)->pd.DataFrame: + def search_queue_for_jobid(self, job_id: int, **kwargs) -> pd.DataFrame: """search_queue_for_jobid this jobs searches the job queue for a certain job id. @@ -142,7 +161,7 @@ def search_queue_for_jobid(self, job_id: int, **kwargs)->pd.DataFrame: NotImplemented Needs to be implemented in subclasses """ - if (self.verbose): + if self.verbose: print("Searching job ID: ", job_id) warnings.warn("Queue search was called, but no queue present!") return [] diff --git a/pygromos/simulations/hpc_queuing/submission_systems/lsf.py b/pygromos/simulations/hpc_queuing/submission_systems/lsf.py index 13055368..96b1eedc 100644 --- a/pygromos/simulations/hpc_queuing/submission_systems/lsf.py +++ b/pygromos/simulations/hpc_queuing/submission_systems/lsf.py @@ -9,45 +9,51 @@ from pygromos.utils import bash from pygromos.utils.utils import time_wait_s_for_filesystem + class LSF(_SubmissionSystem): """LSF - This class is a wrapper for the LSF queueing system by IBM, like it is used on Euler. + This class is a wrapper for the LSF queueing system by IBM, like it is used on Euler. """ - _dummy:bool=False - _refresh_job_queue_list_all_s: int = 60 # update the job-queue list every x seconds + _dummy: bool = False + _refresh_job_queue_list_all_s: int = 60 # update the job-queue list every x seconds _job_queue_time_stamp: datetime - def __init__(self, - submission: bool = True, - nomp: int = 1, - nmpi: int = 1, - job_duration: str = "24:00", - max_storage: float = 1000, - verbose: bool = False, - enviroment=None, - block_double_submission:bool=True, - bjobs_only_same_host:bool=False, - chain_prefix:str="done", - begin_mail:bool=False, - end_mail:bool=False, - zip_trajectories: bool = True): + def __init__( + self, + submission: bool = True, + nomp: int = 1, + nmpi: int = 1, + job_duration: str = "24:00", + max_storage: float = 1000, + verbose: bool = False, + enviroment=None, + block_double_submission: bool = True, + bjobs_only_same_host: bool = False, + chain_prefix: str = "done", + begin_mail: bool = False, + end_mail: bool = False, + zip_trajectories: bool = True, + ): # general settings for the submission system - super().__init__(verbose=verbose, - nmpi=nmpi, nomp=nomp, - job_duration=job_duration, - max_storage=max_storage, - submission=submission, - enviroment=enviroment, - block_double_submission=block_double_submission, - chain_prefix=chain_prefix, - begin_mail=begin_mail, - end_mail=end_mail, - zip_trajectories=zip_trajectories) + super().__init__( + verbose=verbose, + nmpi=nmpi, + nomp=nomp, + job_duration=job_duration, + max_storage=max_storage, + submission=submission, + enviroment=enviroment, + block_double_submission=block_double_submission, + chain_prefix=chain_prefix, + begin_mail=begin_mail, + end_mail=end_mail, + zip_trajectories=zip_trajectories, + ) # Only LSF specific settings: self.bjobs_only_same_host = bjobs_only_same_host - def submit_to_queue(self, sub_job:Submission_job) -> int: + def submit_to_queue(self, sub_job: Submission_job) -> int: """ This function submits the given command to the LSF QUEUE @@ -65,16 +71,22 @@ def submit_to_queue(self, sub_job:Submission_job) -> int: submission_string = "" # QUEUE checking to not double submit - if (self._block_double_submission and self.submission): - if (self.verbose): print('check queue') + if self._block_double_submission and self.submission: + if self.verbose: + print("check queue") ids = list(self.search_queue_for_jobname(sub_job.jobName).index) - if (len(ids) > 0): - if (self.verbose): print( - "\tSKIP - FOUND JOB: \t\t" + "\n\t\t".join(map(str, ids)) + "\n\t\t with jobname: " + sub_job.jobName) + if len(ids) > 0: + if self.verbose: + print( + "\tSKIP - FOUND JOB: \t\t" + + "\n\t\t".join(map(str, ids)) + + "\n\t\t with jobname: " + + sub_job.jobName + ) return ids[0] - if (isinstance(sub_job.submit_from_dir, str) and os.path.isdir(sub_job.submit_from_dir)): + if isinstance(sub_job.submit_from_dir, str) and os.path.isdir(sub_job.submit_from_dir): os.chdir(sub_job.submit_from_dir) command_file_path = sub_job.submit_from_dir + "/job_" + str(sub_job.jobName) + ".sh" else: @@ -84,42 +96,45 @@ def submit_to_queue(self, sub_job:Submission_job) -> int: submission_string += " -J" + sub_job.jobName + " " submission_string += " -W " + str(self.job_duration) + " " - if (not isinstance(sub_job.post_execution_command, type(None))): - submission_string += "-Ep \"" + sub_job.post_execution_command + "\" " + if not isinstance(sub_job.post_execution_command, type(None)): + submission_string += '-Ep "' + sub_job.post_execution_command + '" ' - if (not isinstance(sub_job.outLog, str) and not isinstance(sub_job.errLog, str)): + if not isinstance(sub_job.outLog, str) and not isinstance(sub_job.errLog, str): outLog = sub_job.jobName + ".out" submission_string += " -o " + outLog - elif (isinstance(sub_job.outLog, str)): + elif isinstance(sub_job.outLog, str): submission_string += " -o " + sub_job.outLog - if (isinstance(sub_job.errLog, str)): + if isinstance(sub_job.errLog, str): submission_string += " -e " + sub_job.errLog nCPU = self.nmpi * self.nomp submission_string += " -n " + str(nCPU) + " " add_string = "" # add_string= "-R \"select[model==XeonGold_5118 || model==XeonGold_6150 || model==XeonE3_1585Lv5 || model==XeonE3_1284Lv4 || model==XeonE7_8867v3 || model == XeonGold_6140 || model==XeonGold_6150 ]\"" - if (isinstance(self.max_storage, int)): + if isinstance(self.max_storage, int): submission_string += " -R rusage[mem=" + str(self.max_storage) + "] " - if (isinstance(sub_job.queue_after_jobID, (int, str)) and (sub_job.queue_after_jobID != 0 or sub_job.queue_after_jobID != "0")): - submission_string += " -w \"" + self.chain_prefix + "(" + str(sub_job.queue_after_jobID) + ")\" " + if isinstance(sub_job.queue_after_jobID, (int, str)) and ( + sub_job.queue_after_jobID != 0 or sub_job.queue_after_jobID != "0" + ): + submission_string += ' -w "' + self.chain_prefix + "(" + str(sub_job.queue_after_jobID) + ')" ' - if (self.begin_mail): + if self.begin_mail: submission_string += " -B " - if (self.end_mail): + if self.end_mail: submission_string += " -N " - sub_job.command = sub_job.command.strip() # remove trailing line breaks - - if (self.nomp >= 1): - command = "\"export OMP_NUM_THREADS=" + str(self.nomp) + ";\n " + sub_job.command + "\"" + sub_job.command = sub_job.command.strip() # remove trailing line breaks + + if self.nomp >= 1: + command = '"export OMP_NUM_THREADS=' + str(self.nomp) + ";\n " + sub_job.command + '"' else: command = "\n " + sub_job.command + "" - if (sub_job.sumbit_from_file): - if (self.verbose): print("writing tmp-submission-file to: ", command_file_path) + if sub_job.sumbit_from_file: + if self.verbose: + print("writing tmp-submission-file to: ", command_file_path) command_file = open(command_file_path, "w") command_file.write("#!/bin/bash\n") command_file.write(command + ";\n") @@ -131,8 +146,9 @@ def submit_to_queue(self, sub_job:Submission_job) -> int: ##finalize string submission_string = list(map(lambda x: x.strip(), submission_string.split())) + [command] - if (self.verbose): print("Submission Command: \t", " ".join(submission_string)) - if (self.submission and not self._dummy): + if self.verbose: + print("Submission Command: \t", " ".join(submission_string)) + if self.submission and not self._dummy: try: out_process = bash.execute(command=submission_string, catch_STD=True, env=self._enviroment) std_out = "\n".join(map(str, out_process.stdout.readlines())) @@ -140,13 +156,13 @@ def submit_to_queue(self, sub_job:Submission_job) -> int: # next sopt_job is queued with id: id_start = std_out.find("<") id_end = std_out.find(">") - job_id = int(str(std_out[id_start + 1:id_end]).strip()) - if self.verbose: print("process returned id: " + str(job_id)) - if (str(job_id) == "" and job_id.isalnum()): + job_id = int(str(std_out[id_start + 1 : id_end]).strip()) + if self.verbose: + print("process returned id: " + str(job_id)) + if str(job_id) == "" and job_id.isalnum(): raise ValueError("Did not get at job ID!") except: - raise ChildProcessError("could not submit this command: \n" + - str(submission_string)) + raise ChildProcessError("could not submit this command: \n" + str(submission_string)) else: job_id = -1 @@ -154,7 +170,7 @@ def submit_to_queue(self, sub_job:Submission_job) -> int: sub_job.jobID = job_id return job_id - def submit_jobAarray_to_queue(self, sub_job:Submission_job) -> int: + def submit_jobAarray_to_queue(self, sub_job: Submission_job) -> int: """ This functioncan be used for submission of a job array. The ammount of jobs is determined by the difference: end_job-start_job @@ -173,63 +189,70 @@ def submit_jobAarray_to_queue(self, sub_job:Submission_job) -> int: """ # QUEUE checking to not double submit - if (self.submission and self._block_double_submission): - if (self.verbose): print('check queue') + if self.submission and self._block_double_submission: + if self.verbose: + print("check queue") ids = self.search_queue_for_jobname(sub_job.jobName) - if (len(ids) > 0): - if (self.verbose): print( - "\tSKIP - FOUND JOB: \t\t" + "\n\t\t".join(map(str, ids)) + "\n\t\t with jobname: " + sub_job.jobName) + if len(ids) > 0: + if self.verbose: + print( + "\tSKIP - FOUND JOB: \t\t" + + "\n\t\t".join(map(str, ids)) + + "\n\t\t with jobname: " + + sub_job.jobName + ) return ids[0] # generate submission_string: submission_string = "" - if (isinstance(sub_job.submit_from_dir, str) and os.path.isdir(sub_job.submit_from_dir)): + if isinstance(sub_job.submit_from_dir, str) and os.path.isdir(sub_job.submit_from_dir): submission_string += "cd " + sub_job.submit_from_dir + " && " - if (sub_job.jobLim is None): + if sub_job.jobLim is None: jobLim = sub_job.end_job - sub_job.start_job jobName = str(sub_job.jobName) + "[" + str(sub_job.start_job) + "-" + str(sub_job.end_job) + "]%" + str(jobLim) - submission_string += "bsub -J \" " + jobName + " \" -W \"" + str(self.job_duration) + "\" " + submission_string += 'bsub -J " ' + jobName + ' " -W "' + str(self.job_duration) + '" ' - if (isinstance(sub_job.jobGroup, str)): + if isinstance(sub_job.jobGroup, str): submission_string += " -g " + sub_job.jobGroup + " " - if (not isinstance(sub_job.outLog, str) and not isinstance(sub_job.errLog, str)): + if not isinstance(sub_job.outLog, str) and not isinstance(sub_job.errLog, str): outLog = jobName + ".out" submission_string += " -oo " + outLog - elif (isinstance(sub_job.outLog, str)): + elif isinstance(sub_job.outLog, str): submission_string += " -oo " + sub_job.outLog - if (isinstance(sub_job.errLog, str)): + if isinstance(sub_job.errLog, str): submission_string += " -eo " + sub_job.errLog nCPU = self.nmpi * self.nomp submission_string += " -n " + str(nCPU) + " " - if (isinstance(self.max_storage, int)): - submission_string += " -R \"rusage[mem=" + str(self.max_storage) + "]\" " + if isinstance(self.max_storage, int): + submission_string += ' -R "rusage[mem=' + str(self.max_storage) + ']" ' - if (isinstance(sub_job.queue_after_jobID, (int, str))): - submission_string += " -w " + self.chain_prefix + "(" + str(sub_job.queue_after_jobID) + ")\" " + if isinstance(sub_job.queue_after_jobID, (int, str)): + submission_string += " -w " + self.chain_prefix + "(" + str(sub_job.queue_after_jobID) + ')" ' - if (self.begin_mail): + if self.begin_mail: submission_string += " -B " - if (self.end_mail): + if self.end_mail: submission_string += " -N " - if (self.nomp > 1): - command = " \" export OMP_NUM_THREADS=" + str(self.nomp) + " && " + sub_job.command + "\"" + if self.nomp > 1: + command = ' " export OMP_NUM_THREADS=' + str(self.nomp) + " && " + sub_job.command + '"' else: - command = " \"" + sub_job.command + "\"" + command = ' "' + sub_job.command + '"' ##finalize string submission_string = list(map(lambda x: x.strip(), submission_string.split())) + [command] - if (self.verbose): print("Submission Command: \t", " ".join(submission_string)) - if (self.submission and not self._dummy): + if self.verbose: + print("Submission Command: \t", " ".join(submission_string)) + if self.submission and not self._dummy: try: std_out_buff = bash.execute(command=submission_string, env=self._enviroment) std_out = "\n".join(std_out_buff.readlines()) @@ -237,9 +260,10 @@ def submit_jobAarray_to_queue(self, sub_job:Submission_job) -> int: # next sopt_job is queued with id: id_start = std_out.find("<") id_end = std_out.find(">") - job_id = str(std_out[id_start + 1:id_end]).strip() - if self.verbose: print("process returned id: " + str(job_id)) - if (job_id == "" and job_id.isalnum()): + job_id = str(std_out[id_start + 1 : id_end]).strip() + if self.verbose: + print("process returned id: " + str(job_id)) + if job_id == "" and job_id.isalnum(): raise ValueError("Did not get at job ID!") except: raise ChildProcessError("could not submit this command: \n" + " ".join(submission_string)) @@ -250,20 +274,36 @@ def submit_jobAarray_to_queue(self, sub_job:Submission_job) -> int: def get_script_generation_command(self, var_name: str = None, var_prefixes: str = "") -> str: name = self.__class__.__name__ - if (var_name is None): + if var_name is None: var_name = var_prefixes + name gen_cmd = "#Generate " + name + "\n" gen_cmd += "from " + self.__module__ + " import " + name + " as " + name + "_obj" + "\n" - gen_cmd += var_name + " = " + name + "_obj(submission=" + str(self.submission) + ", verbose=" + str( - self.verbose) + ", nmpi="+str(self.nmpi)+", nomp="+str(self.nomp)+ ", max_storage="+str( - self.max_storage)+", job_duration=\""+str(self.job_duration)+"\")\n\n" + gen_cmd += ( + var_name + + " = " + + name + + "_obj(submission=" + + str(self.submission) + + ", verbose=" + + str(self.verbose) + + ", nmpi=" + + str(self.nmpi) + + ", nomp=" + + str(self.nomp) + + ", max_storage=" + + str(self.max_storage) + + ', job_duration="' + + str(self.job_duration) + + '")\n\n' + ) return gen_cmd """ Job Queue Managment """ - def get_queued_jobs(self)->pd.DataFrame: + + def get_queued_jobs(self) -> pd.DataFrame: """ This function updates the job-list of the queueing system in the class. @@ -274,30 +314,32 @@ def get_queued_jobs(self)->pd.DataFrame: """ # Do we need an update of the job list? check_job_list = True - if (hasattr(self, "_job_queue_time_stamp")): + if hasattr(self, "_job_queue_time_stamp"): last_update = datetime.now() - self._job_queue_time_stamp check_job_list = last_update.seconds > self._refresh_job_queue_list_all_s - if(not self.submission): #shortcut to reduce queue calls! - self.job_queue_list = pd.DataFrame(columns=["JOBID USER STAT QUEUE FROM_HOST EXEC_HOST JOB_NAME SUBMIT_TIME".split()]) - return self.job_queue_list - if (check_job_list): + if not self.submission: # shortcut to reduce queue calls! + self.job_queue_list = pd.DataFrame( + columns=["JOBID USER STAT QUEUE FROM_HOST EXEC_HOST JOB_NAME SUBMIT_TIME".split()] + ) + return self.job_queue_list + if check_job_list: # try getting the lsf queue - if (not self._dummy): + if not self._dummy: try: - #get all running and pending jobs - if self.bjobs_only_same_host: - out_process = bash.execute("bjobs -w", catch_STD=True) - else: - out_process = bash.execute("bjobs -w | grep '$HOSTNAME\|JOBID'", catch_STD=True) - job_list_str = list(map(lambda x: x.decode("utf-8"), out_process.stdout.readlines())) - - #get all finished jobs - if self.bjobs_only_same_host: - out_process = bash.execute("bjobs -wd", catch_STD=True) - else: - out_process = bash.execute("bjobs -wd | grep '$HOSTNAME\|JOBID'", catch_STD=True) - job_list_finished_str = list(map(lambda x: x.decode("utf-8"), out_process.stdout.readlines())) - self._job_queue_time_stamp = datetime.now() + # get all running and pending jobs + if self.bjobs_only_same_host: + out_process = bash.execute("bjobs -w", catch_STD=True) + else: + out_process = bash.execute("bjobs -w | grep '$HOSTNAME\|JOBID'", catch_STD=True) + job_list_str = list(map(lambda x: x.decode("utf-8"), out_process.stdout.readlines())) + + # get all finished jobs + if self.bjobs_only_same_host: + out_process = bash.execute("bjobs -wd", catch_STD=True) + else: + out_process = bash.execute("bjobs -wd | grep '$HOSTNAME\|JOBID'", catch_STD=True) + job_list_finished_str = list(map(lambda x: x.decode("utf-8"), out_process.stdout.readlines())) + self._job_queue_time_stamp = datetime.now() except Exception as err: raise Exception("Could not get job_list!\nerr:\n" + "\n".join(err.args)) else: @@ -307,9 +349,9 @@ def get_queued_jobs(self)->pd.DataFrame: # format information: jlist = list(map(lambda x: x.strip().split(), job_list_str)) jlist_fin = list(map(lambda x: x.strip().split(), job_list_finished_str)) - if(len(jlist) > 1): + if len(jlist) > 1: header = jlist[0] - jobs = jlist[1:]+jlist_fin[1:] + jobs = jlist[1:] + jlist_fin[1:] jobs_dict = {} for job in jobs: @@ -320,24 +362,30 @@ def get_queued_jobs(self)->pd.DataFrame: from_host = job[4] exec_host = job[5] job_name = " ".join(job[6:-3]) - submit_time = datetime.strptime(str(datetime.now().year) + " " + " ".join(job[-3:]), '%Y %b %d %H:%M') + submit_time = datetime.strptime( + str(datetime.now().year) + " " + " ".join(job[-3:]), "%Y %b %d %H:%M" + ) values = [jobID, user, status, queue, from_host, exec_host, job_name, submit_time] jobs_dict.update({jobID: {key: value for key, value in zip(header, values)}}) self.job_queue_list = pd.DataFrame(jobs_dict, index=None).T else: - self.job_queue_list = pd.DataFrame(columns=["JOBID USER STAT QUEUE FROM_HOST EXEC_HOST JOB_NAME SUBMIT_TIME".split()]) + self.job_queue_list = pd.DataFrame( + columns=[ + "JOBID USER STAT QUEUE FROM_HOST EXEC_HOST JOB_NAME SUBMIT_TIME".split() + ] + ) else: - if (self.verbose): + if self.verbose: print("Skipping refresh of job list, as the last update is " + str(last_update) + "s ago") pass return self.job_queue_list - def search_queue_for_jobid(self, job_id:int)->pd.DataFrame: + def search_queue_for_jobid(self, job_id: int) -> pd.DataFrame: self.get_queued_jobs() return self.job_queue_list.where(self.job_queue_list.JOBID == job_id).dropna() - def search_queue_for_jobname(self, job_name:str, regex:bool=False)->pd.DataFrame: + def search_queue_for_jobname(self, job_name: str, regex: bool = False) -> pd.DataFrame: """search_queue_for_jobname this jobs searches the job queue for a certain job name. @@ -354,16 +402,16 @@ def search_queue_for_jobname(self, job_name:str, regex:bool=False)->pd.DataFrame """ self.get_queued_jobs() - if(regex): + if regex: return self.job_queue_list.where(self.job_queue_list.JOB_NAME.str.match(job_name)).dropna() else: return self.job_queue_list.where(self.job_queue_list.JOB_NAME == job_name).dropna() - """ kill jobs """ - def kill_jobs(self, job_name:str=None, regex:bool=False, job_ids: Union[List[int], int]=None): + + def kill_jobs(self, job_name: str = None, regex: bool = False, job_ids: Union[List[int], int] = None): """ this function can be used to terminate or remove pending jobs from the queue. Parameters @@ -377,20 +425,20 @@ def kill_jobs(self, job_name:str=None, regex:bool=False, job_ids: Union[List[int """ - if(not job_name is None): + if not job_name is None: job_ids = list(self.search_queue_for_jobname(job_name, regex=regex).index) - elif(not job_ids is None): - if(isinstance(job_ids, int)): + elif not job_ids is None: + if isinstance(job_ids, int): job_ids = [job_ids] else: raise ValueError("Please provide either job_name or job_ids!") - if(self.verbose): - print("Stopping: "+", ".join(map(str, job_ids))) + if self.verbose: + print("Stopping: " + ", ".join(map(str, job_ids))) try: - bash.execute('bkill '+ " ".join(map(str, job_ids))) + bash.execute("bkill " + " ".join(map(str, job_ids))) except Exception as err: - if(any(["Job has already finished" in x for x in err.args])): + if any(["Job has already finished" in x for x in err.args]): print("Job has already finished") else: raise ChildProcessError("could not execute this command: \n" + str(err.args)) diff --git a/pygromos/simulations/hpc_queuing/submission_systems/submission_job.py b/pygromos/simulations/hpc_queuing/submission_systems/submission_job.py index 91cae145..05dabadd 100644 --- a/pygromos/simulations/hpc_queuing/submission_systems/submission_job.py +++ b/pygromos/simulations/hpc_queuing/submission_systems/submission_job.py @@ -1,4 +1,4 @@ -class Submission_job(): +class Submission_job: """ Description: This class stores parameters for the submission of jobs. It is used by the submission_systems: @@ -12,19 +12,23 @@ class Submission_job(): Author: Marc Lehner """ - def __init__(self, command: str = None, - jobName: str = None, - outLog: str=None, - errLog: str=None, - start_job: int = None, - end_job: int = None, - jobLim:int = None, - queue_after_jobID: int = None, - post_execution_command: str = None, - submit_from_dir: str = None, - sumbit_from_file: bool = True, - jobGroup: str = None, - jobID = None) -> None: + + def __init__( + self, + command: str = None, + jobName: str = None, + outLog: str = None, + errLog: str = None, + start_job: int = None, + end_job: int = None, + jobLim: int = None, + queue_after_jobID: int = None, + post_execution_command: str = None, + submit_from_dir: str = None, + sumbit_from_file: bool = True, + jobGroup: str = None, + jobID=None, + ) -> None: self._command = command self._jobName = jobName self._outLog = outLog @@ -51,7 +55,7 @@ def command(self, command: str) -> None: self._command = command else: raise ValueError("command must be a string") - + @property def jobName(self) -> str: if self._jobName is None: @@ -88,7 +92,7 @@ def jobLim(self, jobLim: int) -> None: @property def queue_after_jobID(self) -> int: return self._queue_after_jobID - + @property def post_execution_command(self) -> str: return self._post_execution_command diff --git a/pygromos/simulations/modules/general_analysis_modules.py b/pygromos/simulations/modules/general_analysis_modules.py index 6e188fa3..a134ab5f 100644 --- a/pygromos/simulations/modules/general_analysis_modules.py +++ b/pygromos/simulations/modules/general_analysis_modules.py @@ -5,4 +5,4 @@ * default analysis for emin ? eq? Start with local submission system first. :) -""" \ No newline at end of file +""" diff --git a/pygromos/simulations/modules/general_simulation_modules.py b/pygromos/simulations/modules/general_simulation_modules.py index 3bb06743..805272af 100644 --- a/pygromos/simulations/modules/general_simulation_modules.py +++ b/pygromos/simulations/modules/general_simulation_modules.py @@ -20,12 +20,24 @@ from pygromos.utils.utils import spacer as spacer, time_wait_s_for_filesystem -def simulation(in_gromos_simulation_system:Gromos_System, override_project_dir:str=None, - step_name:str="sim", in_imd_path:str = None, - submission_system:_SubmissionSystem=LOCAL(), simulation_runs:int=1, equilibration_runs:int = 0, - previous_simulation_run:int=None, force_simulation:bool=False, initialize_first_run= False, reinitialize_every_run= False, - analysis_script:callable = simulation_analysis.do, analysis_control_dict:dict = None, - verbose:bool = True, verbose_lvl:int=1, _template_imd_path:str=None) -> Gromos_System: +def simulation( + in_gromos_simulation_system: Gromos_System, + override_project_dir: str = None, + step_name: str = "sim", + in_imd_path: str = None, + submission_system: _SubmissionSystem = LOCAL(), + simulation_runs: int = 1, + equilibration_runs: int = 0, + previous_simulation_run: int = None, + force_simulation: bool = False, + initialize_first_run=False, + reinitialize_every_run=False, + analysis_script: callable = simulation_analysis.do, + analysis_control_dict: dict = None, + verbose: bool = True, + verbose_lvl: int = 1, + _template_imd_path: str = None, +) -> Gromos_System: """ This function is a generic simulation block, that can be used to run and schedule simulations. @@ -65,13 +77,13 @@ def simulation(in_gromos_simulation_system:Gromos_System, override_project_dir:s Gromos_System, returns a new gromos system which is containing the simulation info """ - #PREPERATIONS + # PREPERATIONS try: try: gromos_system = deepcopy(in_gromos_simulation_system) - #check if override dir is given and set project to correct location - if(not override_project_dir is None): + # check if override dir is given and set project to correct location + if not override_project_dir is None: init_work_folder = override_project_dir step_dir = override_project_dir + "/" + step_name else: @@ -88,16 +100,19 @@ def simulation(in_gromos_simulation_system:Gromos_System, override_project_dir:s gromos_system.work_folder = out_input_dir gromos_system.name = step_name - if(not in_imd_path is None): + if not in_imd_path is None: gromos_system.imd = in_imd_path - elif(hasattr(gromos_system.imd, "TITLE")): + elif hasattr(gromos_system.imd, "TITLE"): pass - elif(not _template_imd_path is None): - if(verbose): warnings.warn("Template_imd_path was used: "+_template_imd_path) + elif not _template_imd_path is None: + if verbose: + warnings.warn("Template_imd_path was used: " + _template_imd_path) gromos_system.imd = _template_imd_path gromos_system.prepare_for_simulation() else: - raise ValueError("Could not find any .imd path (gromos system has no imd, in_imd_path not given and also no _template_imd_path!)") + raise ValueError( + "Could not find any .imd path (gromos system has no imd, in_imd_path not given and also no _template_imd_path!)" + ) out_analysis_cnf = out_analysis_dir + "/data/" + gromos_system.name + ".cnf" @@ -106,32 +121,40 @@ def simulation(in_gromos_simulation_system:Gromos_System, override_project_dir:s print(step_name) print(spacer) - #Write out, all non promised files + # Write out, all non promised files gromos_system.rebase_files() - #Write Out Ana Script + # Write Out Ana Script in_analysis_control_dict = analysis_control_dict - n_analysis_processors = 1 #Maybe in the future: 5 if(nmpi>5) else 1 + n_analysis_processors = 1 # Maybe in the future: 5 if(nmpi>5) else 1 except Exception as err: raise Exception("Could not prepare the gromos System\n\t" + "\n\t".join(map(str, err.args))) # do - if(analysis_script is not None): - analysis_control_dict = simulation_analysis.template_control_dict if (in_analysis_control_dict is None) else in_analysis_control_dict - - analysis_vars = OrderedDict({ - "in_simulation_dir": out_simulation_dir, - "sim_prefix": gromos_system.name, - "out_analysis_dir": out_analysis_dir, - "gromosPP_bin_dir": gromos_system.gromosPP._bin, - "control_dict": analysis_control_dict, - "n_processes": n_analysis_processors, - "verbose": verbose, - "verbose_lvl": verbose_lvl - }) + if analysis_script is not None: + analysis_control_dict = ( + simulation_analysis.template_control_dict + if (in_analysis_control_dict is None) + else in_analysis_control_dict + ) + + analysis_vars = OrderedDict( + { + "in_simulation_dir": out_simulation_dir, + "sim_prefix": gromos_system.name, + "out_analysis_dir": out_analysis_dir, + "gromosPP_bin_dir": gromos_system.gromosPP._bin, + "control_dict": analysis_control_dict, + "n_processes": n_analysis_processors, + "verbose": verbose, + "verbose_lvl": verbose_lvl, + } + ) try: - in_analysis_script_path = utils.write_job_script(out_script_path=step_dir + "/job_analysis.py", - target_function=analysis_script, - variable_dict=analysis_vars) + in_analysis_script_path = utils.write_job_script( + out_script_path=step_dir + "/job_analysis.py", + target_function=analysis_script, + variable_dict=analysis_vars, + ) except Exception as err: raise Exception("Could not prepare the analysis script\n\t" + "\n\t".join(map(str, err.args))) else: @@ -139,49 +162,60 @@ def simulation(in_gromos_simulation_system:Gromos_System, override_project_dir:s ##Write Out schedulling Script ###Build analysis_script - MD_job_vars = OrderedDict({ - "in_simSystem": gromos_system, - "out_dir_path": out_simulation_dir, - "simulation_run_num": simulation_runs, - "equilibration_run_num": equilibration_runs, - "submission_system": submission_system, - "analysis_script_path": in_analysis_script_path, - "initialize_first_run": initialize_first_run, - "reinitialize_every_run": reinitialize_every_run, - "verbose": verbose, - "verbose_lvl": verbose_lvl - }) + MD_job_vars = OrderedDict( + { + "in_simSystem": gromos_system, + "out_dir_path": out_simulation_dir, + "simulation_run_num": simulation_runs, + "equilibration_run_num": equilibration_runs, + "submission_system": submission_system, + "analysis_script_path": in_analysis_script_path, + "initialize_first_run": initialize_first_run, + "reinitialize_every_run": reinitialize_every_run, + "verbose": verbose, + "verbose_lvl": verbose_lvl, + } + ) try: - in_scheduler_script_path = utils.write_job_script(out_script_path=step_dir + "/schedule_MD_job.py", - target_function=simulation_scheduler.do, - variable_dict=MD_job_vars) + in_scheduler_script_path = utils.write_job_script( + out_script_path=step_dir + "/schedule_MD_job.py", + target_function=simulation_scheduler.do, + variable_dict=MD_job_vars, + ) except Exception as err: raise Exception("Could not prepare the scheduling script\n\t" + "\n\t".join(map(str, err.args))) except Exception as err: traceback.print_exception(*sys.exc_info()) - raise Exception("Could not prepare the command block\n\t"+"\n\t".join(map(str, err.args))) + raise Exception("Could not prepare the command block\n\t" + "\n\t".join(map(str, err.args))) ##schedule try: - if((os.path.exists(out_analysis_cnf) and os.path.exists(out_simulation_dir+".tar")) and not force_simulation): + if (os.path.exists(out_analysis_cnf) and os.path.exists(out_simulation_dir + ".tar")) and not force_simulation: if verbose: - print(utils.spacer2+"FOUND RESULT: "+out_analysis_cnf+"\n GOING TO SKIPT THIS SUBMISSION!") - #warnings.warn("Skipping active submission, as result CNF was found: \n"+out_analysis_cnf) + print(utils.spacer2 + "FOUND RESULT: " + out_analysis_cnf + "\n GOING TO SKIPT THIS SUBMISSION!") + # warnings.warn("Skipping active submission, as result CNF was found: \n"+out_analysis_cnf) last_jobID = 0 else: - last_jobID = simulation_scheduler.do(in_simSystem=gromos_system, out_dir_path=out_simulation_dir, - simulation_run_num=simulation_runs, equilibration_run_num=equilibration_runs, - submission_system=submission_system, previous_job_ID=previous_simulation_run, - initialize_first_run= initialize_first_run, reinitialize_every_run= reinitialize_every_run, - analysis_script_path=in_analysis_script_path, verbose=verbose, verbose_lvl=verbose_lvl) + last_jobID = simulation_scheduler.do( + in_simSystem=gromos_system, + out_dir_path=out_simulation_dir, + simulation_run_num=simulation_runs, + equilibration_run_num=equilibration_runs, + submission_system=submission_system, + previous_job_ID=previous_simulation_run, + initialize_first_run=initialize_first_run, + reinitialize_every_run=reinitialize_every_run, + analysis_script_path=in_analysis_script_path, + verbose=verbose, + verbose_lvl=verbose_lvl, + ) except Exception as err: traceback.print_exception(*sys.exc_info()) - raise Exception("Could not submit the commands\n\t"+"\n\t".join(map(str, err.args))) - + raise Exception("Could not submit the commands\n\t" + "\n\t".join(map(str, err.args))) time.sleep(time_wait_s_for_filesystem) # Return the promise final system - if(os.path.exists(out_analysis_cnf)): + if os.path.exists(out_analysis_cnf): gromos_system.cnf = cnf.Cnf(out_analysis_cnf) else: gromos_system.cnf = cnf.Cnf(in_value=None) @@ -189,9 +223,9 @@ def simulation(in_gromos_simulation_system:Gromos_System, override_project_dir:s gromos_system.cnf.path = out_analysis_dir + "/data/" + gromos_system.name + ".cnf" # Return trajectories if available - if(hasattr(gromos_system.imd, "WRITETRAJ") and gromos_system.imd.WRITETRAJ.NTWX > 0): + if hasattr(gromos_system.imd, "WRITETRAJ") and gromos_system.imd.WRITETRAJ.NTWX > 0: final_trc_file = out_analysis_dir + "/data/" + gromos_system.name + ".trc" - if os.path.exists(final_trc_file+".h5"): + if os.path.exists(final_trc_file + ".h5"): gromos_system.trc = Trc(input_value=final_trc_file + ".h5") elif os.path.exists(final_trc_file): gromos_system.trc = Trc(input_value=final_trc_file) @@ -200,9 +234,9 @@ def simulation(in_gromos_simulation_system:Gromos_System, override_project_dir:s gromos_system.trc._future_file = True gromos_system.trc.path = final_trc_file - if(hasattr(gromos_system.imd, "WRITETRAJ") and gromos_system.imd.WRITETRAJ.NTWE > 0): + if hasattr(gromos_system.imd, "WRITETRAJ") and gromos_system.imd.WRITETRAJ.NTWE > 0: final_tre_file = out_analysis_dir + "/data/" + gromos_system.name + ".tre" - if os.path.exists(final_tre_file+".h5"): + if os.path.exists(final_tre_file + ".h5"): gromos_system.tre = Tre(input_value=final_tre_file + ".h5") elif os.path.exists(final_tre_file): gromos_system.tre = Tre(input_value=final_tre_file) @@ -211,9 +245,9 @@ def simulation(in_gromos_simulation_system:Gromos_System, override_project_dir:s gromos_system.tre._future_file = True gromos_system.tre.path = final_tre_file - if(hasattr(gromos_system.imd, "WRITETRAJ") and gromos_system.imd.WRITETRAJ.NTWG > 0): + if hasattr(gromos_system.imd, "WRITETRAJ") and gromos_system.imd.WRITETRAJ.NTWG > 0: final_trg_file = out_analysis_dir + "/data/" + gromos_system.name + ".trg" - if os.path.exists(final_trg_file+".h5"): + if os.path.exists(final_trg_file + ".h5"): gromos_system.trg = Trg(input_value=final_trg_file + ".h5") elif os.path.exists(final_trg_file): gromos_system.trg = Trg(input_value=final_trg_file) diff --git a/pygromos/simulations/modules/preset_simulation_modules.py b/pygromos/simulations/modules/preset_simulation_modules.py index 50cbc763..013ca0ec 100644 --- a/pygromos/simulations/modules/preset_simulation_modules.py +++ b/pygromos/simulations/modules/preset_simulation_modules.py @@ -12,51 +12,121 @@ """ Simulations """ -def emin(in_gromos_system: Gromos_System, step_name: str = "emin", override_project_dir: str=None, in_imd_path=None, - submission_system: _SubmissionSystem = LOCAL(), simulation_runs: int = 1, equilibration_runs: int = 0, - previous_simulation_run: int = None, _template_imd_path:str=template_emin, initialize_first_run= False, - analysis_script: callable = simulation_analysis.do) -> Tuple[Gromos_System, int]: + + +def emin( + in_gromos_system: Gromos_System, + step_name: str = "emin", + override_project_dir: str = None, + in_imd_path=None, + submission_system: _SubmissionSystem = LOCAL(), + simulation_runs: int = 1, + equilibration_runs: int = 0, + previous_simulation_run: int = None, + _template_imd_path: str = template_emin, + initialize_first_run=False, + analysis_script: callable = simulation_analysis.do, +) -> Tuple[Gromos_System, int]: template_emin_control_dict = simulation_analysis.template_control_dict - template_emin_control_dict['concat']['cat_trc'] = False - template_emin_control_dict['concat']['cat_tre'] = False - template_emin_control_dict['concat']['cat_trg'] = False - - if(hasattr(in_gromos_system.imd, "WRITETRAJ")): - if(in_gromos_system.imd.WRITETRAJ.NTWX>0): - template_emin_control_dict['concat']['cat_trc'] = False - if(in_gromos_system.imd.WRITETRAJ.NTWE>0): - template_emin_control_dict['concat']['cat_tre'] = False - if(in_gromos_system.imd.WRITETRAJ.NTWG>0): - template_emin_control_dict['concat']['cat_trg'] = False - - return simulation(in_gromos_simulation_system=in_gromos_system, override_project_dir=override_project_dir, previous_simulation_run=previous_simulation_run, - step_name=step_name, in_imd_path=in_imd_path, submission_system=submission_system, initialize_first_run=initialize_first_run, - simulation_runs=simulation_runs, equilibration_runs=equilibration_runs, analysis_control_dict = template_emin_control_dict, - analysis_script=analysis_script, _template_imd_path=_template_imd_path) - - -def md(in_gromos_system: Gromos_System, step_name: str = "md", override_project_dir: str=None, in_imd_path=None, - submission_system: _SubmissionSystem = LOCAL(), simulation_runs: int = 1, equilibration_runs: int = 0, initialize_first_run= False, reinitialize_every_run= False, - previous_simulation_run: int = None, _template_imd_path:str=template_md, analysis_script: callable = simulation_analysis.do) -> Tuple[Gromos_System, int]: - return simulation(in_gromos_simulation_system=in_gromos_system, override_project_dir=override_project_dir, previous_simulation_run=previous_simulation_run, - step_name=step_name, in_imd_path=in_imd_path, submission_system=submission_system, initialize_first_run=initialize_first_run, - simulation_runs=simulation_runs, equilibration_runs=equilibration_runs, - analysis_script=analysis_script, _template_imd_path=_template_imd_path) - - -def sd(in_gromos_system: Gromos_System, step_name: str = "sd", override_project_dir: str=None, in_imd_path=None, - submission_system: _SubmissionSystem = LOCAL(), simulation_runs: int = 1, equilibration_runs: int = 0, initialize_first_run= False, reinitialize_every_run= False, - previous_simulation_run: int = None, _template_imd_path:str=template_sd, analysis_script: callable = simulation_analysis.do) -> Tuple[Gromos_System, int]: - return simulation(in_gromos_simulation_system=in_gromos_system, override_project_dir=override_project_dir, previous_simulation_run=previous_simulation_run, - step_name=step_name, in_imd_path=in_imd_path, submission_system=submission_system, initialize_first_run=initialize_first_run, - simulation_runs=simulation_runs, equilibration_runs=equilibration_runs, - analysis_script=analysis_script, _template_imd_path=_template_imd_path) - - -def thermalisation(in_gromos_system: Gromos_System, temperatures = np.linspace(60, 300, 4), step_name: str = "eq_therm", override_project_dir: str=None, - in_imd_path=None, - submission_system: _SubmissionSystem = LOCAL(), simulation_runs: int = 1, equilibration_runs: int = 0, - previous_simulation_run: int = None, _template_imd_path:str=template_sd, analysis_script: callable = simulation_analysis.do) -> Tuple[Gromos_System, int]: + template_emin_control_dict["concat"]["cat_trc"] = False + template_emin_control_dict["concat"]["cat_tre"] = False + template_emin_control_dict["concat"]["cat_trg"] = False + + if hasattr(in_gromos_system.imd, "WRITETRAJ"): + if in_gromos_system.imd.WRITETRAJ.NTWX > 0: + template_emin_control_dict["concat"]["cat_trc"] = False + if in_gromos_system.imd.WRITETRAJ.NTWE > 0: + template_emin_control_dict["concat"]["cat_tre"] = False + if in_gromos_system.imd.WRITETRAJ.NTWG > 0: + template_emin_control_dict["concat"]["cat_trg"] = False + + return simulation( + in_gromos_simulation_system=in_gromos_system, + override_project_dir=override_project_dir, + previous_simulation_run=previous_simulation_run, + step_name=step_name, + in_imd_path=in_imd_path, + submission_system=submission_system, + initialize_first_run=initialize_first_run, + simulation_runs=simulation_runs, + equilibration_runs=equilibration_runs, + analysis_control_dict=template_emin_control_dict, + analysis_script=analysis_script, + _template_imd_path=_template_imd_path, + ) + + +def md( + in_gromos_system: Gromos_System, + step_name: str = "md", + override_project_dir: str = None, + in_imd_path=None, + submission_system: _SubmissionSystem = LOCAL(), + simulation_runs: int = 1, + equilibration_runs: int = 0, + initialize_first_run=False, + reinitialize_every_run=False, + previous_simulation_run: int = None, + _template_imd_path: str = template_md, + analysis_script: callable = simulation_analysis.do, +) -> Tuple[Gromos_System, int]: + return simulation( + in_gromos_simulation_system=in_gromos_system, + override_project_dir=override_project_dir, + previous_simulation_run=previous_simulation_run, + step_name=step_name, + in_imd_path=in_imd_path, + submission_system=submission_system, + initialize_first_run=initialize_first_run, + simulation_runs=simulation_runs, + equilibration_runs=equilibration_runs, + analysis_script=analysis_script, + _template_imd_path=_template_imd_path, + ) + + +def sd( + in_gromos_system: Gromos_System, + step_name: str = "sd", + override_project_dir: str = None, + in_imd_path=None, + submission_system: _SubmissionSystem = LOCAL(), + simulation_runs: int = 1, + equilibration_runs: int = 0, + initialize_first_run=False, + reinitialize_every_run=False, + previous_simulation_run: int = None, + _template_imd_path: str = template_sd, + analysis_script: callable = simulation_analysis.do, +) -> Tuple[Gromos_System, int]: + return simulation( + in_gromos_simulation_system=in_gromos_system, + override_project_dir=override_project_dir, + previous_simulation_run=previous_simulation_run, + step_name=step_name, + in_imd_path=in_imd_path, + submission_system=submission_system, + initialize_first_run=initialize_first_run, + simulation_runs=simulation_runs, + equilibration_runs=equilibration_runs, + analysis_script=analysis_script, + _template_imd_path=_template_imd_path, + ) + + +def thermalisation( + in_gromos_system: Gromos_System, + temperatures=np.linspace(60, 300, 4), + step_name: str = "eq_therm", + override_project_dir: str = None, + in_imd_path=None, + submission_system: _SubmissionSystem = LOCAL(), + simulation_runs: int = 1, + equilibration_runs: int = 0, + previous_simulation_run: int = None, + _template_imd_path: str = template_sd, + analysis_script: callable = simulation_analysis.do, +) -> Tuple[Gromos_System, int]: for runID, temperature in enumerate(temperatures): print("run", runID, "T: ", temperature) @@ -65,21 +135,34 @@ def thermalisation(in_gromos_system: Gromos_System, temperatures = np.linspace(6 in_gromos_system.imd.MULTIBATH.TEMP0 = [temperature for x in range(in_gromos_system.imd.MULTIBATH.NBATHS)] # turn off the posres for the last run. - if (runID + 1 == len(temperatures)): + if runID + 1 == len(temperatures): in_gromos_system.imd.POSITIONRES.NTPOR = 0 in_gromos_system.imd.POSITIONRES.CPOR = 0 # Last run - return simulation(in_gromos_simulation_system=in_gromos_system, override_project_dir=override_project_dir, previous_simulation_run=previous_simulation_run, - step_name=step_name, in_imd_path=in_imd_path, submission_system=submission_system, - simulation_runs=simulation_runs, equilibration_runs=equilibration_runs, - analysis_script=analysis_script, _template_imd_path=_template_imd_path) - + return simulation( + in_gromos_simulation_system=in_gromos_system, + override_project_dir=override_project_dir, + previous_simulation_run=previous_simulation_run, + step_name=step_name, + in_imd_path=in_imd_path, + submission_system=submission_system, + simulation_runs=simulation_runs, + equilibration_runs=equilibration_runs, + analysis_script=analysis_script, + _template_imd_path=_template_imd_path, + ) else: - simulation(in_gromos_simulation_system=in_gromos_system, override_project_dir=override_project_dir, previous_simulation_run=previous_simulation_run, - step_name=step_name, in_imd_path=in_imd_path, submission_system=submission_system, - simulation_runs=simulation_runs, equilibration_runs=equilibration_runs, - analysis_script=analysis_script, _template_imd_path=_template_imd_path) - - + simulation( + in_gromos_simulation_system=in_gromos_system, + override_project_dir=override_project_dir, + previous_simulation_run=previous_simulation_run, + step_name=step_name, + in_imd_path=in_imd_path, + submission_system=submission_system, + simulation_runs=simulation_runs, + equilibration_runs=equilibration_runs, + analysis_script=analysis_script, + _template_imd_path=_template_imd_path, + ) diff --git a/pygromos/simulations/modules/ti_modules.py b/pygromos/simulations/modules/ti_modules.py index 31d58258..4e09716c 100644 --- a/pygromos/simulations/modules/ti_modules.py +++ b/pygromos/simulations/modules/ti_modules.py @@ -17,49 +17,57 @@ from pygromos.utils import bash -def TI_sampling(in_gromos_system: Gromos_System, project_dir: str, step_name="lambda_sampling", - lambda_values: List[float] = np.arange(0, 1.1, 0.1), subSystem: _SubmissionSystem = LOCAL(), - n_productions: int = 3, n_equilibrations: int = 1, randomize: bool = False, dual_cnf: List[str] = None): - """ - This function will automatically submit N independent (different lambda) - MD simulations with a lambda dependent potential energy. - - Parameters - ---------- - in_gromos_system: Gromos_System - input gromos system - project_dir: str - directory in which simulation input files are found - step_name: str - subdirectory of project_dir, in which we will write the output - important: allows to run multiple random seeds with a different "step_name" - lambda_values: List [float] - List of lambda values for each independent simulation - subSystem: _SubmissionSystem - where will the calculation run - n_productions: int - number of chunks each independent simulation is broken down into - n_equilibrations: int - number of chunks of equilibration preceding the production for each independent simulation - randomize: bool - Choose a random number for the initial random seed (same for all lambda values) - dual_cnf: List [str], optional - If provided, should be the path to two conformations (matching end states A and B) which - can be used as initial conformations - Simulations with a lambda value between 0 and 0.5 will use the first as starting conformation - - Returns - -------- - lam_system: Gromos_System - Gromos system of the simulation submitted last +def TI_sampling( + in_gromos_system: Gromos_System, + project_dir: str, + step_name="lambda_sampling", + lambda_values: List[float] = np.arange(0, 1.1, 0.1), + subSystem: _SubmissionSystem = LOCAL(), + n_productions: int = 3, + n_equilibrations: int = 1, + randomize: bool = False, + dual_cnf: List[str] = None, +): """ + This function will automatically submit N independent (different lambda) + MD simulations with a lambda dependent potential energy. + + Parameters + ---------- + in_gromos_system: Gromos_System + input gromos system + project_dir: str + directory in which simulation input files are found + step_name: str + subdirectory of project_dir, in which we will write the output + important: allows to run multiple random seeds with a different "step_name" + lambda_values: List [float] + List of lambda values for each independent simulation + subSystem: _SubmissionSystem + where will the calculation run + n_productions: int + number of chunks each independent simulation is broken down into + n_equilibrations: int + number of chunks of equilibration preceding the production for each independent simulation + randomize: bool + Choose a random number for the initial random seed (same for all lambda values) + dual_cnf: List [str], optional + If provided, should be the path to two conformations (matching end states A and B) which + can be used as initial conformations + Simulations with a lambda value between 0 and 0.5 will use the first as starting conformation + Returns + -------- + lam_system: Gromos_System + Gromos system of the simulation submitted last + """ work_dir = bash.make_folder(project_dir + "/" + step_name) - + # Select a random seed here so all lambda windows have the same - if randomize: in_gromos_system.imd.randomize_seed() - + if randomize: + in_gromos_system.imd.randomize_seed() + in_gromos_system.save(work_dir) general_system_name_prefix = in_gromos_system.name @@ -68,10 +76,10 @@ def TI_sampling(in_gromos_system: Gromos_System, project_dir: str, step_name="la lam = np.round(lam, 4) lam_system = deepcopy(in_gromos_system) - lam_system.name = general_system_name_prefix+"_l_" + str(lam) + lam_system.name = general_system_name_prefix + "_l_" + str(lam) lam_system.work_folder = work_dir - - # Choose different conformations depending on lambda point. + + # Choose different conformations depending on lambda point. # e.g. this allows to use RE-EDS SSM conformations. # dual_cnf[i] contains the path of the cnf to use if dual_cnf is not None and lam <= 0.5: @@ -82,22 +90,25 @@ def TI_sampling(in_gromos_system: Gromos_System, project_dir: str, step_name="la # IMD ## Pertubation ###Pertubation of system. - pert_block = PERTURBATION(NTG=1, NRDGL=0, RLAM=lam, DLAMT=0, - ALPHC=0.5, ALPHLJ=0.5, NLAM=2, NSCALE=0) + pert_block = PERTURBATION(NTG=1, NRDGL=0, RLAM=lam, DLAMT=0, ALPHC=0.5, ALPHLJ=0.5, NLAM=2, NSCALE=0) lam_system.imd.add_block(block=pert_block) ###Calculate additional lambda points - if(not hasattr(lam_system, "PRECALCLAM")): + if not hasattr(lam_system, "PRECALCLAM"): # Note: This assumes uniformely distributed lambda values precalc_lam_block = PRECALCLAM(NRLAM=len(lambda_values), MINLAM=0, MAXLAM=1) lam_system.imd.add_block(block=precalc_lam_block) # Submit - out_gromos_system = _TI_lam_step(in_gromos_system=lam_system, project_dir=work_dir, - step_name=lam_system.name, submission_system=subSystem, - in_imd_path=None, - simulation_runs=n_productions, - equilibration_runs=n_equilibrations) + out_gromos_system = _TI_lam_step( + in_gromos_system=lam_system, + project_dir=work_dir, + step_name=lam_system.name, + submission_system=subSystem, + in_imd_path=None, + simulation_runs=n_productions, + equilibration_runs=n_equilibrations, + ) out_gromos_system.save(out_gromos_system.work_folder + "/sd_out_system.obj") lam_systems.append(out_gromos_system) @@ -105,30 +116,43 @@ def TI_sampling(in_gromos_system: Gromos_System, project_dir: str, step_name="la return lam_system -def _TI_lam_step(in_gromos_system: Gromos_System, project_dir: str, step_name: str = "lam", in_imd_path=None, - submission_system: _SubmissionSystem = LOCAL(), simulation_runs: int = 1, equilibration_runs: int = 0, - previous_simulation_run: int = None, analysis_script: callable = simulation_analysis.do) ->(Gromos_System, int): - template_control_dict = OrderedDict({ - "concat": {"do": True, - "sub": { - "cp_cnf": True, - "repair_NaN": True, - "cp_omd": True, - "cat_trc": True, - "cat_tre": True, - "cat_trg": True, - "convert_trcs": False, - } - }, - "simulation_folder": { - "do": False, - "sub": { - "tar": False, - "remove": False - } +def _TI_lam_step( + in_gromos_system: Gromos_System, + project_dir: str, + step_name: str = "lam", + in_imd_path=None, + submission_system: _SubmissionSystem = LOCAL(), + simulation_runs: int = 1, + equilibration_runs: int = 0, + previous_simulation_run: int = None, + analysis_script: callable = simulation_analysis.do, +) -> (Gromos_System, int): + template_control_dict = OrderedDict( + { + "concat": { + "do": True, + "sub": { + "cp_cnf": True, + "repair_NaN": True, + "cp_omd": True, + "cat_trc": True, + "cat_tre": True, + "cat_trg": True, + "convert_trcs": False, + }, + }, + "simulation_folder": {"do": False, "sub": {"tar": False, "remove": False}}, } - }) - return simulation(in_gromos_simulation_system=in_gromos_system, override_project_dir=project_dir, previous_simulation_run=previous_simulation_run, - step_name=step_name, in_imd_path=in_imd_path, submission_system=submission_system, - simulation_runs=simulation_runs, equilibration_runs=equilibration_runs, analysis_control_dict=template_control_dict, - analysis_script=analysis_script) + ) + return simulation( + in_gromos_simulation_system=in_gromos_system, + override_project_dir=project_dir, + previous_simulation_run=previous_simulation_run, + step_name=step_name, + in_imd_path=in_imd_path, + submission_system=submission_system, + simulation_runs=simulation_runs, + equilibration_runs=equilibration_runs, + analysis_control_dict=template_control_dict, + analysis_script=analysis_script, + ) diff --git a/pygromos/tests/in_testfiles/__init__.py b/pygromos/tests/in_testfiles/__init__.py index c4b57180..ca8dfbd6 100644 --- a/pygromos/tests/in_testfiles/__init__.py +++ b/pygromos/tests/in_testfiles/__init__.py @@ -1,2 +1,3 @@ import os + in_test_file_path = os.path.dirname(__file__) diff --git a/pygromos/tests/in_testfiles/imd/emin.imd b/pygromos/tests/in_testfiles/imd/emin.imd index d527c975..32009f38 100644 --- a/pygromos/tests/in_testfiles/imd/emin.imd +++ b/pygromos/tests/in_testfiles/imd/emin.imd @@ -6,65 +6,65 @@ steepest descent energy minimization of the peptide in water END BOUNDCOND # NTB NDFMIN - 1 3 + 1 3 END CONSTRAINT # NTC - 3 + 3 # NTCP NTCP0(1) - 1 0.000100 + 1 0.000100 # NTCS NTCS0(1) - 1 0.000100 + 1 0.000100 END ENERGYMIN # NTEM NCYC DELE DX0 DXM NMIN FLIM - 1 0 0.1 0.01 0.05 2000 0.0 + 1 0 0.1 0.01 0.05 2000 0.0 END FORCE # BONDS ANGLES IMPROPER DIHEDRAL ELECTROSTATIC VDW - 1 1 1 1 1 1 + 1 1 1 1 1 1 # NEGR NRE - 4 71 72 73 2863 + 4 71 72 73 2863 END INITIALISE # NTIVEL NTISHK NTINHT NTINHB - 0 0 0 0 + 0 0 0 0 # NTISHI NTIRTC NTICOM - 1 0 0 + 1 0 0 # NTISTI - 0 + 0 # IG TEMPI - 210185 300.0 + 210185 300.0 END NONBONDED # NLRELE - 1 + 1 # APPAK RCRF EPSRF NSLFEXCL - 0.0 1.4 61 1 + 0.0 1.4 61 1 # NSHAPE ASHAPE NA2CLC TOLA2 EPSLS - -1 1.4 2 1e-10 0 + -1 1.4 2 1e-10 0 # NKX NKY NKZ KCUT - 10 10 10 100 + 10 10 10 100 # NGX NGY NGZ NASORD NFDORD NALIAS NSPORD - 32 32 32 3 2 3 4 + 32 32 32 3 2 3 4 # NQEVAL FACCUR NRDGRD NWRGRD - 100000 1.6 0 0 + 100000 1.6 0 0 # NLRLJ SLVDNS - 0 33.3 + 0 33.3 END PAIRLIST # ALGORITHM NSNB RCUTP RCUTL SIZE TYPE - 0 5 0.800000 1.400000 0.4 0 + 0 5 0.800000 1.400000 0.4 0 END PRINTOUT # NTPR NTPP - 300 0 + 300 0 END STEP # NSTLIM T DT - 3000 0.000000 0.002000 + 3000 0.000000 0.002000 END SYSTEM # NPM NSM - 1 930 + 1 930 END diff --git a/pygromos/tests/in_testfiles/imd/in_REEDS1.imd b/pygromos/tests/in_testfiles/imd/in_REEDS1.imd index 9b9d78c6..5aa115d1 100644 --- a/pygromos/tests/in_testfiles/imd/in_REEDS1.imd +++ b/pygromos/tests/in_testfiles/imd/in_REEDS1.imd @@ -5,41 +5,41 @@ TITLE >>> Generated with python lib function_libs utilities. (riniker group) >>> line_seperator: '\n' field_seperator: '\t' END -BOUNDCOND -# NTB NDFMIN - 1 3 -END -COMTRANSROT -# NSCM - 1000 -END -CONSTRAINT -# NTC - 3 -# NTCP NTCP0(1) - 1 0.0001 -# NTCS NTCS0(1) - 1 0.0001 -END -DISTANCERES -# NTDIR NTDIRA CDIR DIR0 TAUDIR FORCESCALE VDIR NTWDIR - 1 0 1000 1 50 0 0 0 -END -FORCE -# BONDS ANGLES IMPROPER DIHEDRAL ELECTROSTATIC VDW - 0 1 1 1 1 1 -# NEGR NRE - 6 40 80 121 161 203 5747 -END -INITIALISE -# NTIVEL NTISHK NTINHT NTINHB - 0 3 0 0 -# NTISHI NTIRTC NTICOM - 0 0 0 -# NTISTI - 0 -# IG TEMPI - 210185 298 +BOUNDCOND +# NTB NDFMIN + 1 3 +END +COMTRANSROT +# NSCM + 1000 +END +CONSTRAINT +# NTC + 3 +# NTCP NTCP0(1) + 1 0.0001 +# NTCS NTCS0(1) + 1 0.0001 +END +DISTANCERES +# NTDIR NTDIRA CDIR DIR0 TAUDIR FORCESCALE VDIR NTWDIR + 1 0 1000 1 50 0 0 0 +END +FORCE +# BONDS ANGLES IMPROPER DIHEDRAL ELECTROSTATIC VDW + 0 1 1 1 1 1 +# NEGR NRE + 6 40 80 121 161 203 5747 +END +INITIALISE +# NTIVEL NTISHK NTINHT NTINHB + 0 3 0 0 +# NTISHI NTIRTC NTICOM + 0 0 0 +# NTISTI + 0 +# IG TEMPI + 210185 298 END MULTIBATH # ALGORITHM @@ -55,21 +55,21 @@ MULTIBATH 203 1 1 5747 2 2 END -NONBONDED -# NLRELE - 1 -# APPAK RCRF EPSRF NSLFEXCL - 0 1.4 66.7 1 -# NSHAPE ASHAPE NA2CLC TOLA2 EPSLS - 3 1.4 2 1e-10 0 -# NKX NKY NKZ KCUT - 10 10 10 100 -# NGX NGY NGZ NASORD NFDORD NALIAS NSPORD - 32 32 32 3 2 3 4 -# NQEVAL FACCUR NRDGRD NWRGRD - 100000 1.6 0 0 -# NLRLJ SLVDNS - 0 33.3 +NONBONDED +# NLRELE + 1 +# APPAK RCRF EPSRF NSLFEXCL + 0 1.4 66.7 1 +# NSHAPE ASHAPE NA2CLC TOLA2 EPSLS + 3 1.4 2 1e-10 0 +# NKX NKY NKZ KCUT + 10 10 10 100 +# NGX NGY NGZ NASORD NFDORD NALIAS NSPORD + 32 32 32 3 2 3 4 +# NQEVAL FACCUR NRDGRD NWRGRD + 100000 1.6 0 0 +# NLRLJ SLVDNS + 0 33.3 END REPLICA_EDS # REEDS @@ -89,49 +89,49 @@ REPLICA_EDS # NRETRIAL NREQUIL CONT EDS_STAT_OUT PERIODIC 10000 0 1 1 0 END -PAIRLIST -# ALGORITHM NSNB RCUTP RCUTL SIZE TYPE - 0 5 0.8 1.4 0.4 0 -END -PRESSURESCALE -# COUPLE SCALE COMP TAUP VIRIAL - 2 1 0.0004575 0.5 2 -# SEMIANISOTROPIC COUPLINGS(X, Y, Z) - 1 1 1 -# PRES0(1...3,1...3) - 0.06102 0 0 - 0 0.06102 0 - 0 0 0.06102 -END -PRINTOUT -# NTPR NTPP - 5000 0 -END -REPLICA_EDS -# REEDS - 1 -# NRES NUMSTATES - 21 5 -# RES(1 ... NRES) - 1.0 0.766 0.586 0.449 0.344 0.263 0.2015 0.154 0.118 0.0905 0.0693 0.053 0.0406 0.0311 0.0238 0.0182 0.014 0.0107 0.0082 0.0063 0.0048 -# EIR(NUMSTATES x NRES) - 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 - 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 - 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 - 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 - 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -# NRETRIAL NREQUIL CONT EDS_STAT_OUT - 10000 0 1 1 -END -STEP -# NSTLIM T DT - 20 0 0.002 -END -SYSTEM -# NPM NSM - 1 1848 -END -WRITETRAJ -# NTWX NTWSE NTWV NTWF NTWE NTWG NTWB - 5000 0 0 0 20 0 0 +PAIRLIST +# ALGORITHM NSNB RCUTP RCUTL SIZE TYPE + 0 5 0.8 1.4 0.4 0 +END +PRESSURESCALE +# COUPLE SCALE COMP TAUP VIRIAL + 2 1 0.0004575 0.5 2 +# SEMIANISOTROPIC COUPLINGS(X, Y, Z) + 1 1 1 +# PRES0(1...3,1...3) + 0.06102 0 0 + 0 0.06102 0 + 0 0 0.06102 +END +PRINTOUT +# NTPR NTPP + 5000 0 +END +REPLICA_EDS +# REEDS + 1 +# NRES NUMSTATES + 21 5 +# RES(1 ... NRES) + 1.0 0.766 0.586 0.449 0.344 0.263 0.2015 0.154 0.118 0.0905 0.0693 0.053 0.0406 0.0311 0.0238 0.0182 0.014 0.0107 0.0082 0.0063 0.0048 +# EIR(NUMSTATES x NRES) + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 +# NRETRIAL NREQUIL CONT EDS_STAT_OUT + 10000 0 1 1 +END +STEP +# NSTLIM T DT + 20 0 0.002 +END +SYSTEM +# NPM NSM + 1 1848 +END +WRITETRAJ +# NTWX NTWSE NTWV NTWF NTWE NTWG NTWB + 5000 0 0 0 20 0 0 END diff --git a/pygromos/tests/in_testfiles/ptp/com_eds_6ligs.top b/pygromos/tests/in_testfiles/ptp/com_eds_6ligs.top index 46807842..cc099cc4 100644 --- a/pygromos/tests/in_testfiles/ptp/com_eds_6ligs.top +++ b/pygromos/tests/in_testfiles/ptp/com_eds_6ligs.top @@ -1,6 +1,6 @@ TITLE Reduced topology based on com_eds_7ligs.top -using atoms 1:1-35;2:1-33;3:1-30;5:1-34;6:1-35;7:1-31 +using atoms 1:1-35;2:1-33;3:1-30;5:1-34;6:1-35;7:1-31 END PHYSICALCONSTANTS # FPEPSI: 1.0/(4.0*PI*EPS0) (EPS0 is the permittivity of vacuum) diff --git a/pygromos/tests/in_testfiles/ptp/eds.ptp b/pygromos/tests/in_testfiles/ptp/eds.ptp index beeb6090..5cd762d4 100644 --- a/pygromos/tests/in_testfiles/ptp/eds.ptp +++ b/pygromos/tests/in_testfiles/ptp/eds.ptp @@ -1,5 +1,5 @@ TITLE -prep_eds: EDS perturbation topology using: +prep_eds: EDS perturbation topology using: /home/bschroed/code/scripts/test/testfile/ptp/ligand_1.top /home/bschroed/code/scripts/test/testfile/ptp/ligand_2.top /home/bschroed/code/scripts/test/testfile/ptp/ligand_3.top diff --git a/pygromos/tests/in_testfiles/ptp/eds_short.ptp b/pygromos/tests/in_testfiles/ptp/eds_short.ptp index 295a00b1..8df19a66 100644 --- a/pygromos/tests/in_testfiles/ptp/eds_short.ptp +++ b/pygromos/tests/in_testfiles/ptp/eds_short.ptp @@ -1,5 +1,5 @@ TITLE -prep_eds: EDS perturbation topology using: +prep_eds: EDS perturbation topology using: /home/bschroed/code/scripts/test/testfile/ptp/ligand_1.top /home/bschroed/code/scripts/test/testfile/ptp/ligand_2.top /home/bschroed/code/scripts/test/testfile/ptp/ligand_3.top diff --git a/pygromos/tests/in_testfiles/ptp/lam_pert.ptp b/pygromos/tests/in_testfiles/ptp/lam_pert.ptp index 15c56039..411c301c 100644 --- a/pygromos/tests/in_testfiles/ptp/lam_pert.ptp +++ b/pygromos/tests/in_testfiles/ptp/lam_pert.ptp @@ -1,14 +1,14 @@ TITLE -Automatic generated pertubation file. +Automatic generated pertubation file. >>> Generated with python lib function_libs utilities. (riniker group) >>> line_seperator: '\n' field_seperator: '\t' comments_char: '#' END PERTATOMPARAM -# NJLA NPTB = 2 +# NJLA NPTB = 2 26 # state_identifiers # state1 state2 -# NR RES NAME IAC1mass1 CHARGE1 IAC2mass2 CHARGE2 ALPHLJ ALPHCRF +# NR RES NAME IAC1mass1 CHARGE1 IAC2mass2 CHARGE2 ALPHLJ ALPHCRF 1 1 C9 16 15.035 0.05200 22 15.035 0.00000 1.00000 1.00000 2 1 C6 64 12.011 0.21300 22 12.011 0.00000 1.00000 1.00000 3 1 C2 64 12.011 -0.43400 22 12.011 0.00000 1.00000 1.00000 diff --git a/pygromos/tests/in_testfiles/ptp/ligand_1.top b/pygromos/tests/in_testfiles/ptp/ligand_1.top index c99ee410..440c216f 100644 --- a/pygromos/tests/in_testfiles/ptp/ligand_1.top +++ b/pygromos/tests/in_testfiles/ptp/ligand_1.top @@ -1,6 +1,6 @@ TITLE Reduced topology based on /home/bschroed/code/scripts/test/testfile/ptp/com_eds_6ligs.top -using atoms 1:1-35 +using atoms 1:1-35 END PHYSICALCONSTANTS # FPEPSI: 1.0/(4.0*PI*EPS0) (EPS0 is the permittivity of vacuum) diff --git a/pygromos/tests/in_testfiles/ptp/ligand_2.top b/pygromos/tests/in_testfiles/ptp/ligand_2.top index 05bc5cc6..d9228a10 100644 --- a/pygromos/tests/in_testfiles/ptp/ligand_2.top +++ b/pygromos/tests/in_testfiles/ptp/ligand_2.top @@ -1,6 +1,6 @@ TITLE Reduced topology based on /home/bschroed/code/scripts/test/testfile/ptp/com_eds_6ligs.top -using atoms 2:1-33 +using atoms 2:1-33 END PHYSICALCONSTANTS # FPEPSI: 1.0/(4.0*PI*EPS0) (EPS0 is the permittivity of vacuum) diff --git a/pygromos/tests/in_testfiles/ptp/ligand_3.top b/pygromos/tests/in_testfiles/ptp/ligand_3.top index 5fa76f03..f660ba4a 100644 --- a/pygromos/tests/in_testfiles/ptp/ligand_3.top +++ b/pygromos/tests/in_testfiles/ptp/ligand_3.top @@ -1,6 +1,6 @@ TITLE Reduced topology based on /home/bschroed/code/scripts/test/testfile/ptp/com_eds_6ligs.top -using atoms 3:1-30 +using atoms 3:1-30 END PHYSICALCONSTANTS # FPEPSI: 1.0/(4.0*PI*EPS0) (EPS0 is the permittivity of vacuum) diff --git a/pygromos/tests/in_testfiles/ptp/ligand_4.top b/pygromos/tests/in_testfiles/ptp/ligand_4.top index 0a884c98..5a143fb5 100644 --- a/pygromos/tests/in_testfiles/ptp/ligand_4.top +++ b/pygromos/tests/in_testfiles/ptp/ligand_4.top @@ -1,6 +1,6 @@ TITLE Reduced topology based on /home/bschroed/code/scripts/test/testfile/ptp/com_eds_6ligs.top -using atoms 4:1-34 +using atoms 4:1-34 END PHYSICALCONSTANTS # FPEPSI: 1.0/(4.0*PI*EPS0) (EPS0 is the permittivity of vacuum) diff --git a/pygromos/tests/in_testfiles/ptp/ligand_5.top b/pygromos/tests/in_testfiles/ptp/ligand_5.top index 28445428..2b402fa8 100644 --- a/pygromos/tests/in_testfiles/ptp/ligand_5.top +++ b/pygromos/tests/in_testfiles/ptp/ligand_5.top @@ -1,6 +1,6 @@ TITLE Reduced topology based on /home/bschroed/code/scripts/test/testfile/ptp/com_eds_6ligs.top -using atoms 5:1-35 +using atoms 5:1-35 END PHYSICALCONSTANTS # FPEPSI: 1.0/(4.0*PI*EPS0) (EPS0 is the permittivity of vacuum) diff --git a/pygromos/tests/in_testfiles/ptp/ligand_6.top b/pygromos/tests/in_testfiles/ptp/ligand_6.top index 4888f9b8..ad7cbcfb 100644 --- a/pygromos/tests/in_testfiles/ptp/ligand_6.top +++ b/pygromos/tests/in_testfiles/ptp/ligand_6.top @@ -1,6 +1,6 @@ TITLE Reduced topology based on /home/bschroed/code/scripts/test/testfile/ptp/com_eds_6ligs.top -using atoms 6:1-31 +using atoms 6:1-31 END PHYSICALCONSTANTS # FPEPSI: 1.0/(4.0*PI*EPS0) (EPS0 is the permittivity of vacuum) diff --git a/pygromos/tests/in_testfiles/ptp/pert_eds_old.ptp b/pygromos/tests/in_testfiles/ptp/pert_eds_old.ptp index 663b8703..7f0e6a7d 100644 --- a/pygromos/tests/in_testfiles/ptp/pert_eds_old.ptp +++ b/pygromos/tests/in_testfiles/ptp/pert_eds_old.ptp @@ -1,5 +1,5 @@ TITLE -prep_eds: EDS perturbation topology using: +prep_eds: EDS perturbation topology using: 3MXF/3MXF.top 4J3I/4J3I.top 4MR3/4MR3.top diff --git a/pygromos/tests/in_testfiles/qmmm/md.imd b/pygromos/tests/in_testfiles/qmmm/md.imd index 09c83200..a934b069 100644 --- a/pygromos/tests/in_testfiles/qmmm/md.imd +++ b/pygromos/tests/in_testfiles/qmmm/md.imd @@ -2,39 +2,39 @@ TITLE Automatically generated input file dsidler Sat Oct 21 10:51:41 2017 - >>> Generated with PyGromosTools (riniker group) <<< + >>> Generated with PyGromosTools (riniker group) <<< END BOUNDCOND # NTB NDFMIN - 1 3 + 1 3 END COMTRANSROT # NSCM - 1000 + 1000 END CONSTRAINT # NTC - 3 + 3 # NTCP NTCP0(1) - 1 0.000100 + 1 0.000100 # NTCS NTCS0(1) - 1 0.000100 + 1 0.000100 END FORCE # BONDS ANGLES IMPROPER DIHEDRAL ELECTROSTATIC VDW - 0 1 1 1 1 1 + 0 1 1 1 1 1 # NEGR NRE - 1 3613 + 1 3613 END INITIALISE # NTIVEL NTISHK NTINHT NTINHB - 1 3 0 0 + 1 3 0 0 # NTISHI NTIRTC NTICOM - 1 0 0 + 1 0 0 # NTISTI - 0 + 0 # IG TEMPI - 210185 298.000000 + 210185 298.000000 END MULTIBATH # ALGORITHM @@ -50,49 +50,49 @@ MULTIBATH END NONBONDED # NLRELE - 1 + 1 # APPAK RCRF EPSRF NSLFEXCL - 0.000000 1.400000 66.700000 1 + 0.000000 1.400000 66.700000 1 # NSHAPE ASHAPE NA2CLC TOLA2 EPSLS - 3 1.400000 2 1e-10 0.000000 + 3 1.400000 2 1e-10 0.000000 # NKX NKY NKZ KCUT - 10 10 10 100.000000 + 10 10 10 100.000000 # NGX NGY NGZ NASORD NFDORD NALIAS NSPORD - 32 32 32 3 2 3 4 + 32 32 32 3 2 3 4 # NQEVAL FACCUR NRDGRD NWRGRD - 1000 1.600000 0 0 + 1000 1.600000 0 0 # NLRLJ SLVDNS - 0 33.300000 + 0 33.300000 END PAIRLIST # ALGORITHM NSNB RCUTP RCUTL SIZE TYPE - 0 5 0.800000 1.400000 0.4 0 + 0 5 0.800000 1.400000 0.4 0 END PRESSURESCALE # COUPLE SCALE COMP TAUP VIRIAL - 2 1 0.000458 0.500000 2 + 2 1 0.000458 0.500000 2 # SEMIANISOTROPIC COUPLINGS(X, Y, Z) - 1 1 1 + 1 1 1 # PRES0(1...3,1...3) 0.06102 0.0 0.0 0.0 0.06102 0.0 - 0.0 0.0 0.06102 + 0.0 0.0 0.06102 END PRINTOUT # NTPR NTPP - 10 0 + 10 0 END STEP # NSTLIM T DT - 100000 0.000000 0.002000 + 100000 0.000000 0.002000 END SYSTEM # NPM NSM - 1 0 + 1 0 END WRITETRAJ # NTWX NTWSE NTWV NTWF NTWE NTWG NTWB - 200 0 0 0 100 0 0 + 200 0 0 0 100 0 0 END QMMM # NTQMMM NTQMSW RCUTQ NTWQMMM QMLJ MMSCAL diff --git a/pygromos/tests/in_testfiles/repdat/2_ligs_4E96_4J3I_sopt1_2_repdat.dat b/pygromos/tests/in_testfiles/repdat/2_ligs_4E96_4J3I_sopt1_2_repdat.dat index 250a4828..3b15e5f6 100644 --- a/pygromos/tests/in_testfiles/repdat/2_ligs_4E96_4J3I_sopt1_2_repdat.dat +++ b/pygromos/tests/in_testfiles/repdat/2_ligs_4E96_4J3I_sopt1_2_repdat.dat @@ -1,4 +1,4 @@ - REPLICA Exchange Output + REPLICA Exchange Output Number of temperatures: 1 Number of s values: 9 diff --git a/pygromos/tests/in_testfiles/small_system/6J29.cnf b/pygromos/tests/in_testfiles/small_system/6J29.cnf index 70942b92..809b8d96 100644 --- a/pygromos/tests/in_testfiles/small_system/6J29.cnf +++ b/pygromos/tests/in_testfiles/small_system/6J29.cnf @@ -5,7 +5,7 @@ TITLE >>> line_seperator: '\n' field_seperator: '\t' comments_char: '#' END POSITION -# +# 1 6J29 H9 1 0.317518425 0.323672481 -0.003314757 1 6J29 N1 2 0.227431594 0.278160628 0.000130681 1 6J29 H8 3 0.141678225 0.332229616 0.000171306 diff --git a/pygromos/tests/in_testfiles/small_system/6J29.top b/pygromos/tests/in_testfiles/small_system/6J29.top index 6d405697..888a844a 100644 --- a/pygromos/tests/in_testfiles/small_system/6J29.top +++ b/pygromos/tests/in_testfiles/small_system/6J29.top @@ -125,7 +125,7 @@ SOLUTEATOM 21 24 26 4 16 19 22 27 6 1 C7 64 12.011 0.54 1 6 7 8 9 16 18 20 - + 5 10 14 17 21 26 7 1 O1 62 15.9994 -0.557 1 1 8 3 9 16 20 @@ -136,7 +136,7 @@ SOLUTEATOM 19 20 3 13 17 21 10 1 C3 64 12.011 -0.106 1 6 11 12 13 14 16 18 - + 3 15 19 20 11 1 H3 20 1.008 0.128 1 1 12 3 13 14 18 @@ -3313,7 +3313,7 @@ PRESSUREGROUPS 27 END LJEXCEPTIONS -# This block defines special LJ-interactions based on atom numbers +# This block defines special LJ-interactions based on atom numbers # This overrules the normal LJ-parameters (including 1-4 interactions) # NEX: number of exceptions 0 diff --git a/pygromos/tests/in_testfiles/top/disres5.disres b/pygromos/tests/in_testfiles/top/disres5.disres index 39c6f702..ff8f4cff 100644 --- a/pygromos/tests/in_testfiles/top/disres5.disres +++ b/pygromos/tests/in_testfiles/top/disres5.disres @@ -3,9 +3,9 @@ generated disres file for BRD4 with PYMOL wizard >>> Generated with python lib function_libs utilities. (riniker group) >>> line_seperator: ' \n' field_seperator: ' \t ' END -DISTANCERESSPEC -# KDISH KDISC - 0.1 0.153 +DISTANCERESSPEC +# KDISH KDISC + 0.1 0.153 # i j k l type i j k l type r0 w0 rah ## KL1/C11 15 - KL17/C11 55 15 0 0 0 0 55 0 0 0 0 0.00300 1.00000 1 diff --git a/pygromos/tests/in_testfiles/top/simpleTest.top b/pygromos/tests/in_testfiles/top/simpleTest.top index 100091cf..a97dee4d 100644 --- a/pygromos/tests/in_testfiles/top/simpleTest.top +++ b/pygromos/tests/in_testfiles/top/simpleTest.top @@ -297,7 +297,7 @@ PRESSUREGROUPS 18 END LJEXCEPTIONS -# This block defines special LJ-interactions based on atom numbers +# This block defines special LJ-interactions based on atom numbers # This overrules the normal LJ-parameters (including 1-4 interactions) # NEX: number of exceptions 0 diff --git a/pygromos/tests/in_testfiles/top/test.top b/pygromos/tests/in_testfiles/top/test.top index 39dec9f8..a17da1f7 100644 --- a/pygromos/tests/in_testfiles/top/test.top +++ b/pygromos/tests/in_testfiles/top/test.top @@ -86,8 +86,8 @@ RESNAME 271 # AANM: residue names KL1 -KL17 -KL19 +KL17 +KL19 KL20 KL21 GLU diff --git a/pygromos/tests/in_testfiles/tre/in_lam.tre b/pygromos/tests/in_testfiles/tre/in_lam.tre index d34a5eaa..1360fa7c 100644 --- a/pygromos/tests/in_testfiles/tre/in_lam.tre +++ b/pygromos/tests/in_testfiles/tre/in_lam.tre @@ -540,4 +540,4 @@ VOLUMEPRESSURE03 1.794308067e+03 3.661088971e+00 6.116577748e+00 3.661088971e+00 2.055278792e+03 -1.443615729e+01 6.116577748e+00 -1.443615729e+01 1.841219565e+03 -END \ No newline at end of file +END diff --git a/pygromos/tests/in_testfiles/tre/in_tre1.tre b/pygromos/tests/in_testfiles/tre/in_tre1.tre index bd848de7..feaaaf03 100644 --- a/pygromos/tests/in_testfiles/tre/in_tre1.tre +++ b/pygromos/tests/in_testfiles/tre/in_tre1.tre @@ -715,4 +715,4 @@ VOLUMEPRESSURE03 1.492231883e+03 -3.546286246e+01 -1.206828321e+01 -3.546286246e+01 1.563821736e+03 2.734471164e+01 -1.206828321e+01 2.734471164e+01 1.441103942e+03 -END \ No newline at end of file +END diff --git a/pygromos/tests/in_testfiles/trg/test.trg b/pygromos/tests/in_testfiles/trg/test.trg index dbad3cc9..d01e0eaa 100644 --- a/pygromos/tests/in_testfiles/trg/test.trg +++ b/pygromos/tests/in_testfiles/trg/test.trg @@ -790,4 +790,4 @@ FREEENERDERIVS03 # ABdih # A_dihedral B_dihedral 0.000000000e+00 0.000000000e+00 -END \ No newline at end of file +END diff --git a/pygromos/tests/out_testresults/__init__.py b/pygromos/tests/out_testresults/__init__.py index 3cc109c8..d8ceaab4 100644 --- a/pygromos/tests/out_testresults/__init__.py +++ b/pygromos/tests/out_testresults/__init__.py @@ -1,2 +1,3 @@ import os + test_dirs = os.path.dirname(__file__) diff --git a/pygromos/tests/test_analysis/test_error_estimate.py b/pygromos/tests/test_analysis/test_error_estimate.py index 673fd318..682868b5 100644 --- a/pygromos/tests/test_analysis/test_error_estimate.py +++ b/pygromos/tests/test_analysis/test_error_estimate.py @@ -2,6 +2,7 @@ import numpy as np import unittest + class test_ee(unittest.TestCase): error_estimate_class = error_estimator test_array = np.arange(10000) @@ -12,4 +13,4 @@ def test_constructor(self): def test_error_estimate(self): # Create array error_estimate = self.error_estimate_class(self.test_array).calculate_error_estimate() - np.testing.assert_almost_equal(desired=866.5903464697677, actual=error_estimate, decimal=2) \ No newline at end of file + np.testing.assert_almost_equal(desired=866.5903464697677, actual=error_estimate, decimal=2) diff --git a/pygromos/tests/test_analysis/test_freeEnergy.py b/pygromos/tests/test_analysis/test_freeEnergy.py index 97a39882..b3e13a3a 100644 --- a/pygromos/tests/test_analysis/test_freeEnergy.py +++ b/pygromos/tests/test_analysis/test_freeEnergy.py @@ -2,7 +2,8 @@ import unittest -from pygromos.analysis.free_energy_calculation import zwanzigEquation, threeStateZwanzig, bennetAcceptanceRatio +from pygromos.analysis.free_energy_calculation import zwanzigEquation, threeStateZwanzig, bennetAcceptanceRatio + class test_ZwanzigEquation(unittest.TestCase): feCalculation = zwanzigEquation @@ -103,7 +104,6 @@ def test_free_Energy1(self): class test_threeStateZwanzigReweighting(test_ZwanzigEquation): feCalculation = threeStateZwanzig - def test_free_Energy1(self): feCalc = self.feCalculation(kT=True) @@ -122,12 +122,24 @@ def test_free_Energy1(self): energy_off_state = 10 noise_off_state = 0.01 - V1 = np.concatenate([np.random.normal(state_1, state_1_noise, sample_state1), - np.random.normal(energy_off_state, noise_off_state, sample_state2)]) - V2 = np.concatenate([np.random.normal(energy_off_state, noise_off_state, sample_state1), - np.random.normal(state_2, state_2_noise, sample_state2)]) - Vr = np.concatenate([np.random.normal(state_1, state_1_noise, sample_state1), - np.random.normal(state_2, state_2_noise, sample_state2)]) + V1 = np.concatenate( + [ + np.random.normal(state_1, state_1_noise, sample_state1), + np.random.normal(energy_off_state, noise_off_state, sample_state2), + ] + ) + V2 = np.concatenate( + [ + np.random.normal(energy_off_state, noise_off_state, sample_state1), + np.random.normal(state_2, state_2_noise, sample_state2), + ] + ) + Vr = np.concatenate( + [ + np.random.normal(state_1, state_1_noise, sample_state1), + np.random.normal(state_2, state_2_noise, sample_state2), + ] + ) dF_ana = state_2 - state_1 dFRew_zwanz = feCalc.calculate(Vi=V1, Vj=V2, Vr=Vr) diff --git a/pygromos/tests/test_approaches/test_solvation_free_ernergy.py b/pygromos/tests/test_approaches/test_solvation_free_ernergy.py index be5f9994..a578e2f7 100644 --- a/pygromos/tests/test_approaches/test_solvation_free_ernergy.py +++ b/pygromos/tests/test_approaches/test_solvation_free_ernergy.py @@ -1,24 +1,30 @@ -from pygromos.simulations.approaches.solvation_free_energy_calculation.solvation_free_energy import Solvation_free_energy_calculation +from pygromos.simulations.approaches.solvation_free_energy_calculation.solvation_free_energy import ( + Solvation_free_energy_calculation, +) from pygromos.files.gromos_system.ff.forcefield_system import forcefield_system import numpy as np import unittest + class test_sfe(unittest.TestCase): - smiles = 'c1ccccc1' - workfolder = '/tmp/test_solvation_free_energy' + smiles = "c1ccccc1" + workfolder = "/tmp/test_solvation_free_energy" number_of_atoms = 12 - sf = Solvation_free_energy_calculation(input_system=smiles, # Gromos_System, SMILES (str) or rdkit Mol - work_folder=workfolder, # Folder to do calculations in - system_name=smiles, - # Name of the system (does not need to be smiles but convenient) - forcefield=forcefield_system("openforcefield"), # Force field to use - density=789, # density of the liquid in kg/L - num_molecules=512, # number of molecules used for the calculation - num_atoms=number_of_atoms, # number of atoms in one molecule - nmpi=1, nomp=1, # number of mpi and omp cores - subsystem="local", # Subsystem to use for calculation local or lsf - amberscaling=True) # Whether to use amberscaling (for openforcefield recommended) + sf = Solvation_free_energy_calculation( + input_system=smiles, # Gromos_System, SMILES (str) or rdkit Mol + work_folder=workfolder, # Folder to do calculations in + system_name=smiles, + # Name of the system (does not need to be smiles but convenient) + forcefield=forcefield_system("openforcefield"), # Force field to use + density=789, # density of the liquid in kg/L + num_molecules=512, # number of molecules used for the calculation + num_atoms=number_of_atoms, # number of atoms in one molecule + nmpi=1, + nomp=1, # number of mpi and omp cores + subsystem="local", # Subsystem to use for calculation local or lsf + amberscaling=True, + ) # Whether to use amberscaling (for openforcefield recommended) def test_constructor(self): print(self.sf) @@ -43,4 +49,3 @@ def test_ptp_file(self): def test_box_generation(self): self.sf.create_liq() - diff --git a/pygromos/tests/test_files/general_file_functions.py b/pygromos/tests/test_files/general_file_functions.py index 2685f361..2de24ee5 100644 --- a/pygromos/tests/test_files/general_file_functions.py +++ b/pygromos/tests/test_files/general_file_functions.py @@ -6,10 +6,11 @@ class general_file_tests(unittest.TestCase): __test__ = False + def test_pickle(self): obj_file = self.class_type(self.in_file_path) - out_path =self.root_out+"/pickleTest.obj" + out_path = self.root_out + "/pickleTest.obj" pickle.dump(obj=obj_file, file=open(out_path, "wb")) obj_loaded = pickle.load(open(out_path, "rb")) @@ -36,8 +37,8 @@ def test_equality(self): def test_equalAfterCopy(self): obj_file = self.class_type(self.in_file_path) obj_copy = copy.deepcopy(obj_file) - #TODO fix + # TODO fix if isinstance(obj_file, Pertubation_topology): pass else: - self.assertEqual(obj_file, obj_copy) \ No newline at end of file + self.assertEqual(obj_file, obj_copy) diff --git a/pygromos/tests/test_files/test_cnf_funcs.py b/pygromos/tests/test_files/test_cnf_funcs.py index 8e486888..f7faf826 100644 --- a/pygromos/tests/test_files/test_cnf_funcs.py +++ b/pygromos/tests/test_files/test_cnf_funcs.py @@ -4,13 +4,16 @@ from pygromos.utils import bash from pygromos.tests.in_testfiles import in_test_file_path -in_file_path= in_test_file_path+"/cnf/in_cnf1.cnf" -in_file_renum_path = in_test_file_path+"/cnf/in_renumber_ligs.cnf" + +in_file_path = in_test_file_path + "/cnf/in_cnf1.cnf" +in_file_renum_path = in_test_file_path + "/cnf/in_renumber_ligs.cnf" from pygromos.tests.test_files import out_test_root_dir + root_out = tempfile.mkdtemp(dir=out_test_root_dir, prefix="cnf_") -out_path = root_out+"/out_cnf1.cnf" -out_red_path = root_out+"/out_cnf1_reduced.cnf" +out_path = root_out + "/out_cnf1.cnf" +out_red_path = root_out + "/out_cnf1_reduced.cnf" + class test_cnf(general_file_tests): __test__ = True @@ -33,12 +36,12 @@ def test_clean_posiResNumsByName(self): cnf_file.clean_posiResNums() residues = cnf_file.get_residues() - #print(residues) + # print(residues) self.assertEqual(2, len(residues), "Found more/less than two residues!") - self.assertEqual(2, list(residues["3U5L"].keys())[0], "Could not recognzize expected resNum for 3U5l = 2" ) - self.assertEqual(1, list(residues["3MXF"].keys())[0], "Could not recognzize expected resNum for 3MXF = 1" ) - self.assertEqual(31, residues["3U5L"][2], "Could not recognzize expected atom ammount for 3U5l = 2" ) - self.assertEqual(35, residues["3MXF"][1], "Could not recognzize expected atom ammount for 3MXF = 1" ) + self.assertEqual(2, list(residues["3U5L"].keys())[0], "Could not recognzize expected resNum for 3U5l = 2") + self.assertEqual(1, list(residues["3MXF"].keys())[0], "Could not recognzize expected resNum for 3MXF = 1") + self.assertEqual(31, residues["3U5L"][2], "Could not recognzize expected atom ammount for 3U5l = 2") + self.assertEqual(35, residues["3MXF"][1], "Could not recognzize expected atom ammount for 3MXF = 1") def test_write_out(self): cnf_file = cnf.Cnf(in_file_path) diff --git a/pygromos/tests/test_files/test_disres.py b/pygromos/tests/test_files/test_disres.py index 22ba9b99..86b86d4b 100644 --- a/pygromos/tests/test_files/test_disres.py +++ b/pygromos/tests/test_files/test_disres.py @@ -6,12 +6,14 @@ from pygromos.tests.in_testfiles import in_test_file_path -root_in = in_test_file_path+"/top" -in_path = root_in+"/disres5.disres" + +root_in = in_test_file_path + "/top" +in_path = root_in + "/disres5.disres" from pygromos.tests.test_files import out_test_root_dir + root_out = tempfile.mkdtemp(dir=out_test_root_dir, prefix="top_") -out_path = root_out+"/out_imd_REEDS1.imd" +out_path = root_out + "/out_imd_REEDS1.imd" class test_disres(general_file_tests): diff --git a/pygromos/tests/test_files/test_disres_file.py b/pygromos/tests/test_files/test_disres_file.py index 46681d27..540b43b0 100644 --- a/pygromos/tests/test_files/test_disres_file.py +++ b/pygromos/tests/test_files/test_disres_file.py @@ -5,12 +5,15 @@ from pygromos.tests.test_files.general_file_functions import general_file_tests from pygromos.tests.in_testfiles import in_test_file_path -root_in =in_test_file_path+"/disres" -in_path = root_in+"/in_disres.dat" + +root_in = in_test_file_path + "/disres" +in_path = root_in + "/in_disres.dat" from pygromos.tests.test_files import out_test_root_dir + root_out = tempfile.mkdtemp(dir=out_test_root_dir, prefix="disres_") -out_path = root_out+"/out_disres.dat" +out_path = root_out + "/out_disres.dat" + class test_disres(general_file_tests): __test__ = True diff --git a/pygromos/tests/test_files/test_gromosSystem.py b/pygromos/tests/test_files/test_gromosSystem.py index 070f9d58..dbbe5de1 100644 --- a/pygromos/tests/test_files/test_gromosSystem.py +++ b/pygromos/tests/test_files/test_gromosSystem.py @@ -8,6 +8,7 @@ from pygromos.data.simulation_parameters_templates import template_md from pygromos.tests.test_files import out_test_root_dir + tmp_test_dir = tempfile.mkdtemp(dir=out_test_root_dir, prefix="gromSystem_") @@ -16,45 +17,64 @@ class test_gromos_system(unittest.TestCase): class_type = Gromos_System verbose = True - input_cnf_path = in_test_file_path+"/small_system/6J29.cnf" - input_top_path = in_test_file_path+"/small_system/6J29.top" + input_cnf_path = in_test_file_path + "/small_system/6J29.cnf" + input_top_path = in_test_file_path + "/small_system/6J29.top" def test_construct_empty(self): subSys = self.class_type(work_folder=tmp_test_dir, system_name="Testing1") print(subSys) def test_construct_files(self): - subSys_files = self.class_type(work_folder=tmp_test_dir, system_name="Testing1", - in_cnf_path=self.input_cnf_path, in_top_path=self.input_top_path) - - subSys_files2 = self.class_type(work_folder=tmp_test_dir, system_name="Testing2", - in_cnf_path=self.input_cnf_path, in_top_path=self.input_top_path, - in_imd_path=template_md) - + subSys_files = self.class_type( + work_folder=tmp_test_dir, + system_name="Testing1", + in_cnf_path=self.input_cnf_path, + in_top_path=self.input_top_path, + ) + + subSys_files2 = self.class_type( + work_folder=tmp_test_dir, + system_name="Testing2", + in_cnf_path=self.input_cnf_path, + in_top_path=self.input_top_path, + in_imd_path=template_md, + ) print(subSys_files2) def setUp(self) -> None: - self.subSys_files = self.class_type(work_folder=tmp_test_dir, system_name="Testing", - in_cnf_path=self.input_cnf_path, in_top_path=self.input_top_path, - in_imd_path=template_md) + self.subSys_files = self.class_type( + work_folder=tmp_test_dir, + system_name="Testing", + in_cnf_path=self.input_cnf_path, + in_top_path=self.input_top_path, + in_imd_path=template_md, + ) def test_rebase(self): - new_base = bash.make_folder(tmp_test_dir+"/rebase") + new_base = bash.make_folder(tmp_test_dir + "/rebase") self.subSys_files.work_folder = new_base self.subSys_files.rebase_files() def test_write(self): - subSys_files2 = self.class_type(work_folder=tmp_test_dir, system_name="Testing2", - in_cnf_path=self.input_cnf_path, in_top_path=self.input_top_path, - in_imd_path=template_md) - subSys_files2.save(tmp_test_dir+"/out_gromSystem.obj") + subSys_files2 = self.class_type( + work_folder=tmp_test_dir, + system_name="Testing2", + in_cnf_path=self.input_cnf_path, + in_top_path=self.input_top_path, + in_imd_path=template_md, + ) + subSys_files2.save(tmp_test_dir + "/out_gromSystem.obj") def test_load(self): - subSys_files2 = self.class_type(work_folder=tmp_test_dir, system_name="Testing2", - in_cnf_path=self.input_cnf_path, in_top_path=self.input_top_path, - in_imd_path=template_md) - load_path = subSys_files2.save(tmp_test_dir+"/out_gromSystem2.obj") + subSys_files2 = self.class_type( + work_folder=tmp_test_dir, + system_name="Testing2", + in_cnf_path=self.input_cnf_path, + in_top_path=self.input_top_path, + in_imd_path=template_md, + ) + load_path = subSys_files2.save(tmp_test_dir + "/out_gromSystem2.obj") grom_sys = self.class_type.load(load_path) - print(grom_sys) \ No newline at end of file + print(grom_sys) diff --git a/pygromos/tests/test_files/test_gromosSystem_forcefields.py b/pygromos/tests/test_files/test_gromosSystem_forcefields.py index 37ed133e..87e47e79 100644 --- a/pygromos/tests/test_files/test_gromosSystem_forcefields.py +++ b/pygromos/tests/test_files/test_gromosSystem_forcefields.py @@ -4,9 +4,10 @@ from pygromos.files.gromos_system.ff.forcefield_system import forcefield_system from pygromos.tests.test_files import out_test_root_dir + tmp_test_dir = tempfile.mkdtemp(dir=out_test_root_dir, prefix="gromSystem_ff_") -if (importlib.util.find_spec("openforcefield") != None): +if importlib.util.find_spec("openforcefield") != None: has_openff = True else: has_openff = False @@ -16,31 +17,41 @@ class test_gromos_system_forcefields(unittest.TestCase): file_class = Gromos_System verbose = True - smiles="CO" - ff=forcefield_system() + smiles = "CO" + ff = forcefield_system() ff.mol_name = "MTL" - def test_construct_empty(self): grSys = self.file_class(work_folder=tmp_test_dir, system_name="Testing1", Forcefield=self.ff) print(grSys) def test_construct_top_from_ff(self): - grSys = self.file_class(work_folder=tmp_test_dir, system_name="Testing1", Forcefield=self.ff, in_smiles=self.smiles, auto_convert=True) + grSys = self.file_class( + work_folder=tmp_test_dir, + system_name="Testing1", + Forcefield=self.ff, + in_smiles=self.smiles, + auto_convert=True, + ) print(grSys) + class test_gromos_system_54A7(test_gromos_system_forcefields): ff = forcefield_system(name="54A7") ff.mol_name = "CH3OH" + class test_gromos_system_2016H66(test_gromos_system_forcefields): ff = forcefield_system(name="2016H66") ff.mol_name = "MTL" + if has_openff: + class test_gromos_system_openforcefield(test_gromos_system_forcefields): ff = forcefield_system(name="off") + """ #TODO: include as soon as serenityff is in production state class test_gromos_system_serenityforcefield(test_gromos_system_forcefields): diff --git a/pygromos/tests/test_files/test_imd.py b/pygromos/tests/test_files/test_imd.py index f3b0ccf0..06daab38 100644 --- a/pygromos/tests/test_files/test_imd.py +++ b/pygromos/tests/test_files/test_imd.py @@ -6,12 +6,14 @@ from pygromos.tests.in_testfiles import in_test_file_path -root_in = in_test_file_path+"/imd" -in_path = root_in+"/in_REEDS1.imd" + +root_in = in_test_file_path + "/imd" +in_path = root_in + "/in_REEDS1.imd" from pygromos.tests.test_files import out_test_root_dir + root_out = tempfile.mkdtemp(dir=out_test_root_dir, prefix="imd_") -out_path = root_out+"/out_imd_REEDS1.imd" +out_path = root_out + "/out_imd_REEDS1.imd" class test_imd(general_file_tests): @@ -29,17 +31,21 @@ def test_to_string(self): print(imd_file) return 0 - def test_edit_REEDS(self): imd_file = self.class_type(self.in_file_path) svals = "1.0 1.0 1.0 1.0".split() - EIR = 0.0 # # - EIR_VECTOR = [0.0, 0.1, 0.2, 0.3, 0.4, ] #write dev cases! + EIR = 0.0 # # + EIR_VECTOR = [ + 0.0, + 0.1, + 0.2, + 0.3, + 0.4, + ] # write dev cases! EIR = EIR_VECTOR imd_file.edit_REEDS(SVALS=svals, EIR=EIR) return 0 - def test_write_out(self): imd_file = self.class_type(self.in_file_path) imd_file.TITLE.content = "NEW TEST!" diff --git a/pygromos/tests/test_files/test_imd_block.py b/pygromos/tests/test_files/test_imd_block.py index ccc9bcc2..34ae9f78 100644 --- a/pygromos/tests/test_files/test_imd_block.py +++ b/pygromos/tests/test_files/test_imd_block.py @@ -1,15 +1,17 @@ import unittest from pygromos.files.blocks import imd_blocks -class test_imd_block(unittest.TestCase): +class test_imd_block(unittest.TestCase): def test_some_blocks(self): - test = imd_blocks.REPLICA_EDS( NRES=2, NUMSTATES=5, RES=6, EIR=8, - NRETRIAL=9, NREQUIL=10, CONT=11) + test = imd_blocks.REPLICA_EDS(NRES=2, NUMSTATES=5, RES=6, EIR=8, NRETRIAL=9, NREQUIL=10, CONT=11) - test2 = imd_blocks.MULTIBATH(ALGORITHM = 1, NBATHS = 1, TEMP0 = [3], TAU = [4], DOFSET = 5, LAST = [6], COMBATH = [6], IRBATH = [7]) + test2 = imd_blocks.MULTIBATH( + ALGORITHM=1, NBATHS=1, TEMP0=[3], TAU=[4], DOFSET=5, LAST=[6], COMBATH=[6], IRBATH=[7] + ) - test3 = imd_blocks.PRESSURESCALE(COUPLE=1, SCALE = 2, COMP =1, TAUP = 1, VIRIAL = 3, SEMIANISOTROPIC= [4], - PRES0 = [[1,0,0],[0,1,0],[0,0,1]]) + test3 = imd_blocks.PRESSURESCALE( + COUPLE=1, SCALE=2, COMP=1, TAUP=1, VIRIAL=3, SEMIANISOTROPIC=[4], PRES0=[[1, 0, 0], [0, 1, 0], [0, 0, 1]] + ) - test4 = imd_blocks.RANDOMNUMBERS(NTRNG=0,NTGSL=0) + test4 = imd_blocks.RANDOMNUMBERS(NTRNG=0, NTGSL=0) diff --git a/pygromos/tests/test_files/test_ptp.py b/pygromos/tests/test_files/test_ptp.py index 0a3800ee..eb8011e5 100644 --- a/pygromos/tests/test_files/test_ptp.py +++ b/pygromos/tests/test_files/test_ptp.py @@ -9,17 +9,20 @@ from pygromos.tests.in_testfiles import in_test_file_path -in_path= in_test_file_path + "/ptp/eds.ptp" + +in_path = in_test_file_path + "/ptp/eds.ptp" in_path2 = in_test_file_path + "/ptp/lam_pert.ptp" from pygromos.tests.test_files import out_test_root_dir + root_out = tempfile.mkdtemp(dir=out_test_root_dir, prefix="ptp_") -outpath=root_out +"/out_ptp.ptp" -outpath_less_state=root_out+"/out_ptp_lessStates.ptp" -outpath_less_atom=root_out+"/out_ptp_lessAtoms.ptp" -outpath_new_atom=root_out+"/out_ptp_newAtoms.ptp" -outpath_new_build=root_out+"/out_ptp_newBuild.ptp" -outpath_new_build_complex=root_out+"/out_ptp_newBuild_complex.ptp" +outpath = root_out + "/out_ptp.ptp" +outpath_less_state = root_out + "/out_ptp_lessStates.ptp" +outpath_less_atom = root_out + "/out_ptp_lessAtoms.ptp" +outpath_new_atom = root_out + "/out_ptp_newAtoms.ptp" +outpath_new_build = root_out + "/out_ptp_newBuild.ptp" +outpath_new_build_complex = root_out + "/out_ptp_newBuild_complex.ptp" + class test_ptp(general_file_tests): __test__ = True @@ -37,19 +40,23 @@ def test_get_eds_states(self): states = ptp.MPERTATOM.states print(states) - def test_add_eds_state(self): - from pygromos.files.blocks.pertubation_blocks import atom_eds_pertubation_state, pertubation_eds_state + from pygromos.files.blocks.pertubation_blocks import atom_eds_pertubation_state, pertubation_eds_state + ptp = self.class_type(in_path) on_state = pertubation_eds_state(IAC=16, CHARGE=-1.0) - new_atoms_state = [atom_eds_pertubation_state(NR=x, NAME="H", STATES={7:on_state, 13:on_state}) if x == 1 else atom_eds_pertubation_state(NR=x, NAME="H", STATES={7:on_state}) for x in range(1, 4)] + new_atoms_state = [ + atom_eds_pertubation_state(NR=x, NAME="H", STATES={7: on_state, 13: on_state}) + if x == 1 + else atom_eds_pertubation_state(NR=x, NAME="H", STATES={7: on_state}) + for x in range(1, 4) + ] ptp.MPERTATOM.add_state_atoms(state_atoms=new_atoms_state) ptp.write(outpath_new_atom) - def test_delete_eds_state(self): ptp = self.class_type(in_path) ptp.MPERTATOM.delete_state(stateIDs=6) @@ -62,7 +69,12 @@ def test_remove_eds_atoms(self): ptp.write(outpath_less_atom) def test_new_eds_ptp_from_scratch(self): - from pygromos.files.blocks.pertubation_blocks import atom_eds_pertubation_state, pertubation_eds_state, MPERTATOM + from pygromos.files.blocks.pertubation_blocks import ( + atom_eds_pertubation_state, + pertubation_eds_state, + MPERTATOM, + ) + ptp = self.class_type() on_state = pertubation_eds_state(IAC=16, CHARGE=-1.0) @@ -83,10 +95,7 @@ def test_eds_gen_all_states_ptp(self): ## Map for molecule ID with Atom IDS ### First atom assumed to be O and last two Hs - molecules_atoms = {1: [1, 2, 3], - 2: [4, 5, 6], - 3: [7, 8, 9], - 4: [10, 11, 12]} + molecules_atoms = {1: [1, 2, 3], 2: [4, 5, 6], 3: [7, 8, 9], 4: [10, 11, 12]} # BUILD UP STATES ## Generate active state mapping: @@ -103,20 +112,19 @@ def test_eds_gen_all_states_ptp(self): new_atoms_state_dict = {} for state, molecules in molecule_states.items(): for molecule in molecules: - if (molecule in new_atoms_state_dict): + if molecule in new_atoms_state_dict: atoms = new_atoms_state_dict[molecule] atoms[0].STATES.update({state: o_state}) atoms[1].STATES.update({state: h_state}) atoms[2].STATES.update({state: h_state}) else: - atoms = [atom_eds_pertubation_state(NR=molecules_atoms[molecule][0], NAME="O", STATES={state: o_state}), - atom_eds_pertubation_state(NR=molecules_atoms[molecule][1], NAME="H1", - STATES={state: h_state}), - atom_eds_pertubation_state(NR=molecules_atoms[molecule][2], NAME="H2", - STATES={state: h_state})] + atoms = [ + atom_eds_pertubation_state(NR=molecules_atoms[molecule][0], NAME="O", STATES={state: o_state}), + atom_eds_pertubation_state(NR=molecules_atoms[molecule][1], NAME="H1", STATES={state: h_state}), + atom_eds_pertubation_state(NR=molecules_atoms[molecule][2], NAME="H2", STATES={state: h_state}), + ] new_atoms_state_dict.update({molecule: atoms}) - ##finally make a list for our ptp file (#ThanksGromos) new_atoms_state = np.concatenate(list(new_atoms_state_dict.values())) @@ -126,4 +134,4 @@ def test_eds_gen_all_states_ptp(self): print(ptp) ptp.write(outpath_new_build_complex) - # TADAAAAA - DONE \ No newline at end of file + # TADAAAAA - DONE diff --git a/pygromos/tests/test_files/test_qmmm.py b/pygromos/tests/test_files/test_qmmm.py index f8eca642..cbd1199a 100644 --- a/pygromos/tests/test_files/test_qmmm.py +++ b/pygromos/tests/test_files/test_qmmm.py @@ -5,14 +5,16 @@ from pygromos.tests.in_testfiles import in_test_file_path -root_in = in_test_file_path+"/qmmm" -in_path_imd = root_in+"/md.imd" -in_path_qmmm = root_in+"/menthol-methanol-dmf.qmmm" + +root_in = in_test_file_path + "/qmmm" +in_path_imd = root_in + "/md.imd" +in_path_qmmm = root_in + "/menthol-methanol-dmf.qmmm" from pygromos.tests.test_files import out_test_root_dir + root_out = tempfile.mkdtemp(dir=out_test_root_dir, prefix="qmmm_") -out_path_imd = root_out+"/out_qmmm.imd" -out_path_qmmm = root_out+"/out_qmmm.qmmm" +out_path_imd = root_out + "/out_qmmm.imd" +out_path_qmmm = root_out + "/out_qmmm.qmmm" class test_qmmm_imd(general_file_tests): @@ -36,6 +38,7 @@ def test_write_out(self): imd_file.write(out_path_imd) return 0 + class test_qmmm(general_file_tests): __test__ = True class_type = qmmm.QMMM diff --git a/pygromos/tests/test_files/test_repdat.py b/pygromos/tests/test_files/test_repdat.py index 5767c417..81dd5b02 100644 --- a/pygromos/tests/test_files/test_repdat.py +++ b/pygromos/tests/test_files/test_repdat.py @@ -4,19 +4,21 @@ from pygromos.tests.test_files.general_file_functions import general_file_tests from pygromos.tests.in_testfiles import in_test_file_path + in_dir = in_test_file_path + "/repdat" -in_path = in_dir+"/in_REEDS_repdat2_short.dat" -in_path2 = in_dir+"/2_ligs_4E96_4J3I_sopt1_2_repdat.dat" +in_path = in_dir + "/in_REEDS_repdat2_short.dat" +in_path2 = in_dir + "/2_ligs_4E96_4J3I_sopt1_2_repdat.dat" from pygromos.tests.test_files import out_test_root_dir + root_out = tempfile.mkdtemp(dir=out_test_root_dir, prefix="repdat_") -out_path = root_out+"/out_REEDS_repdat2_short.dat" -out_path_clean = root_out+"/out_REEDS_repdat2_cleaned_cat.dat" -out_plot1 = root_out+"/out_REEDS_repdat2_transitions.png" -out_plot2 = root_out+"/out_REEDS_repdat2_transitions2.png" +out_path = root_out + "/out_REEDS_repdat2_short.dat" +out_path_clean = root_out + "/out_REEDS_repdat2_cleaned_cat.dat" +out_plot1 = root_out + "/out_REEDS_repdat2_transitions.png" +out_plot2 = root_out + "/out_REEDS_repdat2_transitions2.png" -class test_repdat(unittest.TestCase): #general_file_tests): #Todo: make copy and deepcopy + pickable +class test_repdat(unittest.TestCase): # general_file_tests): #Todo: make copy and deepcopy + pickable __test__ = True class_type = repdat.Repdat in_file_path = in_path @@ -33,7 +35,6 @@ def test_write_out(self): repdat_file = self.class_type(self.in_file_path) repdat_file.write(out_path=out_path) - def test_cleaning_concat(self): repdat_file = self.class_type(self.in_file_path) tmp_size1 = repdat_file.DATA.shape[0] @@ -41,7 +42,7 @@ def test_cleaning_concat(self): repdat_file2 = repdat.Repdat(in_path) - #concat and clean + # concat and clean repdat_file.append(repdat_file2) tmp_size2 = repdat_file.DATA.shape[0] @@ -49,15 +50,15 @@ def test_cleaning_concat(self): repdat_file.write(out_path=out_path_clean) - #print("\nrepdats:\t size:\t", tmp_size1, "\truns:\t", tmp_run1) - #print("repdats:\t size:\t", tmp_size2, "\truns:\t", tmp_run2) - #print(repdat_file.DATA[:][:20]) - #print(repdat_file.DATA[:][-20:]) + # print("\nrepdats:\t size:\t", tmp_size1, "\truns:\t", tmp_run1) + # print("repdats:\t size:\t", tmp_size2, "\truns:\t", tmp_run2) + # print(repdat_file.DATA[:][:20]) + # print(repdat_file.DATA[:][-20:]) - #check_concat - self.assertEqual(2*tmp_size1, tmp_size2) - #check_renumbering - self.assertEqual(2*tmp_run1, tmp_run2) + # check_concat + self.assertEqual(2 * tmp_size1, tmp_size2) + # check_renumbering + self.assertEqual(2 * tmp_run1, tmp_run2) def test_get_transitions(self): repdat_file = self.class_type(self.in_file_path) @@ -66,4 +67,3 @@ def test_get_transitions(self): def test_test_transitions(self): repdat_file = self.class_type(self.in_file_path) transitions = repdat_file.get_replica_traces() - diff --git a/pygromos/tests/test_files/test_resnlib.py b/pygromos/tests/test_files/test_resnlib.py index dbdb8473..54307d62 100644 --- a/pygromos/tests/test_files/test_resnlib.py +++ b/pygromos/tests/test_files/test_resnlib.py @@ -5,11 +5,13 @@ from pygromos.tests.test_files.general_file_functions import general_file_tests -#from pygromos.tests.in_testfiles import in_test_file_path +# from pygromos.tests.in_testfiles import in_test_file_path from pygromos.tests.test_files import out_test_root_dir + root_out = tempfile.mkdtemp(dir=out_test_root_dir, prefix="resnLib_") -outpath=root_out +"/out_lib.resnlib" +outpath = root_out + "/out_lib.resnlib" + class test_resnlib(general_file_tests): __test__ = True diff --git a/pygromos/tests/test_files/test_top.py b/pygromos/tests/test_files/test_top.py index 79e2f06b..16e0c6ab 100644 --- a/pygromos/tests/test_files/test_top.py +++ b/pygromos/tests/test_files/test_top.py @@ -6,13 +6,15 @@ from pygromos.tests.in_testfiles import in_test_file_path -root_in = in_test_file_path+"/top" -in_path = root_in+"/test.top" -simple_path = root_in+"/simpleTest.top" + +root_in = in_test_file_path + "/top" +in_path = root_in + "/test.top" +simple_path = root_in + "/simpleTest.top" from pygromos.tests.test_files import out_test_root_dir + root_out = tempfile.mkdtemp(dir=out_test_root_dir, prefix="top_") -out_path = root_out+"/out_imd_REEDS1.imd" +out_path = root_out + "/out_imd_REEDS1.imd" class test_top(general_file_tests): diff --git a/pygromos/tests/test_files/test_trajectory.py b/pygromos/tests/test_files/test_trajectory.py index 7d601c4c..59ee56cc 100644 --- a/pygromos/tests/test_files/test_trajectory.py +++ b/pygromos/tests/test_files/test_trajectory.py @@ -8,8 +8,10 @@ from pygromos.tests.in_testfiles import in_test_file_path from pygromos.tests.test_files import out_test_root_dir + root_out = tempfile.mkdtemp(dir=out_test_root_dir, prefix="trajs_") + class traj_standard_tests(unittest.TestCase): class_name: gt._General_Trajectory = gt._General_Trajectory in_file_path = in_file_h5_path = None @@ -31,8 +33,8 @@ def test_constructor_trg_h5_file_path(self): print(t) def test_write(self): - if (hasattr(self, 't')): - getattr(self, 't').write(self.outpath) + if hasattr(self, "t"): + getattr(self, "t").write(self.outpath) else: pass @@ -40,7 +42,7 @@ def setUp(self) -> None: self.t1 = self.class_name(input_value=self.in_file_path, auto_save=False) def test_add(self): - if("traj_standard_tests" == self.__class__.__name__): + if "traj_standard_tests" == self.__class__.__name__: return 0 # addition tre_3 = self.t1 + self.t1 @@ -51,18 +53,18 @@ def test_add(self): class test_trc(traj_standard_tests): class_name = trc.Trc - in_file_path = in_test_file_path+ "/trc/in_test.trc" - in_file_h5_path = in_test_file_path+ "/trc/in_test.trc.h5" + in_file_path = in_test_file_path + "/trc/in_test.trc" + in_file_h5_path = in_test_file_path + "/trc/in_test.trc.h5" outpath = root_out + "/out_trc1.trc.h5" class test_tre(traj_standard_tests): class_name = tre.Tre - in_file_path = in_test_file_path+ "/tre/in_tre1.tre" - in_file2_path = in_test_file_path+ "/tre/in_tre2.tre" - in_file_eds_path = in_test_file_path+ "/tre/in_eds.tre" - in_file_lam_path = in_test_file_path+ "/tre/in_lam.tre" - in_file_h5_path = in_test_file_path+ "/tre/in_tre1.tre.h5" + in_file_path = in_test_file_path + "/tre/in_tre1.tre" + in_file2_path = in_test_file_path + "/tre/in_tre2.tre" + in_file_eds_path = in_test_file_path + "/tre/in_eds.tre" + in_file_lam_path = in_test_file_path + "/tre/in_lam.tre" + in_file_h5_path = in_test_file_path + "/tre/in_tre1.tre.h5" outpath = root_out + "/out_tre1.tre.h5" def test_get_totals(self): @@ -78,7 +80,7 @@ def test_get_eds(self): print(eds_ene.shape) self.assertEqual(eds_ene.numstates[0], 9, msg="Number of num_states should be two") - self.assertEqual(eds_ene.shape, (10,37), msg="The traj should have 500 timesteps and 23 fields for precalclam") + self.assertEqual(eds_ene.shape, (10, 37), msg="The traj should have 500 timesteps and 23 fields for precalclam") pass def test_get_lam(self): @@ -86,14 +88,14 @@ def test_get_lam(self): lam_ene = t.get_precalclam() print(lam_ene, lam_ene.shape) self.assertEqual(lam_ene.nr_lambdas[0], 2, msg="Number of lambdas should be two") - self.assertEqual(lam_ene.shape, (5,25), msg="The traj should have 5 timesteps and 23 fields for precalclam") + self.assertEqual(lam_ene.shape, (5, 25), msg="The traj should have 5 timesteps and 23 fields for precalclam") class test_trg(traj_standard_tests): class_name = trg.Trg - in_file_path = in_test_file_path+ "/trg/test.trg" - in_file_h5_path = in_test_file_path+ "/trg/test.trg.h5" - outpath = root_out + "/out_tre1.tre.h5" + in_file_path = in_test_file_path + "/trg/test.trg" + in_file_h5_path = in_test_file_path + "/trg/test.trg.h5" + outpath = root_out + "/out_tre1.tre.h5" # Test Get functions diff --git a/pygromos/tests/test_pygromos.py b/pygromos/tests/test_pygromos.py index 1fc2b23f..127fd399 100644 --- a/pygromos/tests/test_pygromos.py +++ b/pygromos/tests/test_pygromos.py @@ -7,6 +7,7 @@ import pytest import sys + def test_pygromos_imported(): """Sample dev, will always pass so long as import statement worked""" assert "pygromos" in sys.modules diff --git a/pygromos/tests/test_simulation_blocks/__init__.py b/pygromos/tests/test_simulation_blocks/__init__.py index e4596fe1..f1913787 100644 --- a/pygromos/tests/test_simulation_blocks/__init__.py +++ b/pygromos/tests/test_simulation_blocks/__init__.py @@ -2,4 +2,3 @@ from pygromos.tests.out_testresults import test_dirs out_test_root_dir = tempfile.mkdtemp(dir=test_dirs, prefix="tmp_simulation_blocks_") - diff --git a/pygromos/tests/test_simulation_blocks/test_simulation_runner_blocks.py b/pygromos/tests/test_simulation_blocks/test_simulation_runner_blocks.py index ef6b336c..167ba409 100644 --- a/pygromos/tests/test_simulation_blocks/test_simulation_runner_blocks.py +++ b/pygromos/tests/test_simulation_blocks/test_simulation_runner_blocks.py @@ -10,47 +10,74 @@ from pygromos.tests.test_simulation_blocks import out_test_root_dir + class test_simulation_blocks(unittest.TestCase): submissionSystem = DUMMY() sim_block = preset_simulation_modules.emin - input_cnf_path = in_test_file_path+"/small_system/6J29.cnf" - input_top_path = in_test_file_path+"/small_system/6J29.top" + input_cnf_path = in_test_file_path + "/small_system/6J29.cnf" + input_top_path = in_test_file_path + "/small_system/6J29.top" def setUp(self) -> None: self.tmp_test_dir = out_test_root_dir - self.gromSystem = Gromos_System(work_folder=self.tmp_test_dir, system_name=str(__name__), - in_cnf_path=self.input_cnf_path, in_top_path=self.input_top_path) + self.gromSystem = Gromos_System( + work_folder=self.tmp_test_dir, + system_name=str(__name__), + in_cnf_path=self.input_cnf_path, + in_top_path=self.input_top_path, + ) print(self.gromSystem) def test_smulation(self): from pygromos.data.simulation_parameters_templates import template_md + self.gromSystem.imd = template_md - pygromos.simulations.modules.general_simulation_modules.simulation(in_gromos_simulation_system=self.gromSystem, override_project_dir=self.tmp_test_dir, - submission_system=self.submissionSystem) + pygromos.simulations.modules.general_simulation_modules.simulation( + in_gromos_simulation_system=self.gromSystem, + override_project_dir=self.tmp_test_dir, + submission_system=self.submissionSystem, + ) def test_emin(self): - preset_simulation_modules.emin(in_gromos_system=self.gromSystem, override_project_dir=self.tmp_test_dir, - submission_system=self.submissionSystem) + preset_simulation_modules.emin( + in_gromos_system=self.gromSystem, + override_project_dir=self.tmp_test_dir, + submission_system=self.submissionSystem, + ) def test_sd(self): - preset_simulation_modules.sd(in_gromos_system=self.gromSystem, override_project_dir=self.tmp_test_dir, - submission_system=self.submissionSystem) + preset_simulation_modules.sd( + in_gromos_system=self.gromSystem, + override_project_dir=self.tmp_test_dir, + submission_system=self.submissionSystem, + ) def test_md(self): - preset_simulation_modules.md(in_gromos_system=self.gromSystem, override_project_dir=self.tmp_test_dir, - submission_system=self.submissionSystem) + preset_simulation_modules.md( + in_gromos_system=self.gromSystem, + override_project_dir=self.tmp_test_dir, + submission_system=self.submissionSystem, + ) def test_lam_window(self): from pygromos.data import simulation_parameters_templates as imd_templates - pygromos.simulations.modules.ti_modules._TI_lam_step(in_gromos_system=self.gromSystem, project_dir=self.tmp_test_dir, in_imd_path=imd_templates.template_md, - submission_system=self.submissionSystem) + pygromos.simulations.modules.ti_modules._TI_lam_step( + in_gromos_system=self.gromSystem, + project_dir=self.tmp_test_dir, + in_imd_path=imd_templates.template_md, + submission_system=self.submissionSystem, + ) def test_ti_sampling(self): from pygromos.data.simulation_parameters_templates import template_md self.gromSystem.imd = template_md - pygromos.simulations.modules.ti_modules.TI_sampling(in_gromos_system=self.gromSystem, project_dir=self.tmp_test_dir, - lambda_values = np.arange(0, 1.1, 0.1), subSystem = self.submissionSystem, - n_productions = 3, n_equilibrations = 1) + pygromos.simulations.modules.ti_modules.TI_sampling( + in_gromos_system=self.gromSystem, + project_dir=self.tmp_test_dir, + lambda_values=np.arange(0, 1.1, 0.1), + subSystem=self.submissionSystem, + n_productions=3, + n_equilibrations=1, + ) diff --git a/pygromos/tests/test_submission/__init__.py b/pygromos/tests/test_submission/__init__.py index 7af68dfb..18d81936 100644 --- a/pygromos/tests/test_submission/__init__.py +++ b/pygromos/tests/test_submission/__init__.py @@ -2,4 +2,3 @@ from pygromos.tests.out_testresults import test_dirs out_test_root_dir = tempfile.mkdtemp(dir=test_dirs, prefix="tmp_hpc_queuing_") - diff --git a/pygromos/tests/test_submission/test_hpc_queuing_submission_job.py b/pygromos/tests/test_submission/test_hpc_queuing_submission_job.py index 385418aa..b09ee796 100644 --- a/pygromos/tests/test_submission/test_hpc_queuing_submission_job.py +++ b/pygromos/tests/test_submission/test_hpc_queuing_submission_job.py @@ -1,29 +1,31 @@ import unittest from pygromos.simulations.hpc_queuing.submission_systems.submission_job import Submission_job + class test_queuing_system(unittest.TestCase): file_class = Submission_job def test_construct_min(self): - sub_job = self.file_class(command="echo \" WUHAHAHA\"") + sub_job = self.file_class(command='echo " WUHAHAHA"') def test_construct_full(self): - sub_job = self.file_class(command="echo \" WUHAHAHA\"", - jobName="test_job", - start_job=1, - end_job=10, - jobLim=20, - outLog="/dev/null/out.log", - errLog="/dev/null/err.log", - queue_after_jobID=1, - post_execution_command="echo \" WUHAHAHA2\"", - submit_from_dir=".", - sumbit_from_file=True - ) + sub_job = self.file_class( + command='echo " WUHAHAHA"', + jobName="test_job", + start_job=1, + end_job=10, + jobLim=20, + outLog="/dev/null/out.log", + errLog="/dev/null/err.log", + queue_after_jobID=1, + post_execution_command='echo " WUHAHAHA2"', + submit_from_dir=".", + sumbit_from_file=True, + ) def test_acces(self): - sub_job = self.file_class(command="echo \" WUHAHAHA\"", queue_after_jobID=1) + sub_job = self.file_class(command='echo " WUHAHAHA"', queue_after_jobID=1) id = sub_job.queue_after_jobID - assert(isinstance(id, int)) - assert(id == 1) - assert(sub_job.command == "echo \" WUHAHAHA\"") \ No newline at end of file + assert isinstance(id, int) + assert id == 1 + assert sub_job.command == 'echo " WUHAHAHA"' diff --git a/pygromos/tests/test_submission/test_hpc_queuing_submission_scheduling.py b/pygromos/tests/test_submission/test_hpc_queuing_submission_scheduling.py index 31d79e6d..0e961619 100644 --- a/pygromos/tests/test_submission/test_hpc_queuing_submission_scheduling.py +++ b/pygromos/tests/test_submission/test_hpc_queuing_submission_scheduling.py @@ -10,20 +10,32 @@ from pygromos.tests.in_testfiles import in_test_file_path from pygromos.tests.test_files import out_test_root_dir + class test_MD_scheduler(unittest.TestCase): submissionSystem = DUMMY + def setUp(self) -> None: self.tmp_test_dir = tempfile.mkdtemp(dir=out_test_root_dir, prefix="scheduling_Dummy_") def test_do(self): - in_cnf = in_test_file_path+"/cnf/in_cnf1.cnf" - out_dir_path = self.tmp_test_dir + in_cnf = in_test_file_path + "/cnf/in_cnf1.cnf" + out_dir_path = self.tmp_test_dir - in_simSystem = Gromos_System(system_name="test_do", work_folder=out_dir_path, - in_top_path=blank_topo_template, in_cnf_path=in_cnf, in_imd_path=template_md, - in_gromosXX_bin_dir=None, in_gromosPP_bin_dir=None) - submission_system = self.submissionSystem() + in_simSystem = Gromos_System( + system_name="test_do", + work_folder=out_dir_path, + in_top_path=blank_topo_template, + in_cnf_path=in_cnf, + in_imd_path=template_md, + in_gromosXX_bin_dir=None, + in_gromosPP_bin_dir=None, + ) + submission_system = self.submissionSystem() - simulation_scheduler.do(in_simSystem=in_simSystem, out_dir_path=out_dir_path, - submission_system=submission_system, - simulation_run_num=2, verbose= True) + simulation_scheduler.do( + in_simSystem=in_simSystem, + out_dir_path=out_dir_path, + submission_system=submission_system, + simulation_run_num=2, + verbose=True, + ) diff --git a/pygromos/tests/test_submission/test_hpc_queuing_submission_systems.py b/pygromos/tests/test_submission/test_hpc_queuing_submission_systems.py index 8bc6bffb..631684e1 100644 --- a/pygromos/tests/test_submission/test_hpc_queuing_submission_systems.py +++ b/pygromos/tests/test_submission/test_hpc_queuing_submission_systems.py @@ -16,25 +16,19 @@ def test_construct(self): subSys = self.file_class(verbose=self.verbose, submission=self.submission) def test_submit(self): - sub_job = Submission_job(jobName="test_job", command="echo \" WUHAHAHA\"") + sub_job = Submission_job(jobName="test_job", command='echo " WUHAHAHA"') subSys = self.file_class(verbose=self.verbose, submission=self.submission) subSys.submit_to_queue(sub_job=sub_job) def test_submit_jobAarray_to_queue(self): - sub_job = Submission_job(jobName="test_job", - command="echo \" WUHAHAHA\"", - start_job=1, - end_job=1) - + sub_job = Submission_job(jobName="test_job", command='echo " WUHAHAHA"', start_job=1, end_job=1) + subSys = self.file_class(verbose=self.verbose, submission=self.submission) subSys.submit_jobAarray_to_queue(sub_job=sub_job) def test_submit_jobAarray_to_queue1_10(self): - sub_job2 = Submission_job(jobName="test_job", - command="echo \" WUHAHAHA\"", - start_job=1, - end_job=10) + sub_job2 = Submission_job(jobName="test_job", command='echo " WUHAHAHA"', start_job=1, end_job=10) subSys = self.file_class(verbose=self.verbose, submission=self.submission) subSys.submit_jobAarray_to_queue(sub_job=sub_job2) @@ -52,13 +46,16 @@ def test_get_jobs_from_queue(self): subSys = self.file_class(verbose=self.verbose, submission=self.submission) subSys.get_jobs_from_queue(job_text=get_jobs_with) + class test_DUMMY(test_queuing_system): file_class = DUMMY + class test_LOCAL(test_queuing_system): submission = False file_class = LOCAL + class test_LSF(test_queuing_system): submission = False - file_class = LSF \ No newline at end of file + file_class = LSF diff --git a/pygromos/utils/amino_acids.py b/pygromos/utils/amino_acids.py index 329cc7ff..d755baf2 100644 --- a/pygromos/utils/amino_acids.py +++ b/pygromos/utils/amino_acids.py @@ -8,61 +8,105 @@ """ from collections import namedtuple + ions = ["NA+", "CL-"] # add here new amino acid features. -amino_acid:namedtuple = namedtuple("amino_acid", ["name", "oneLetter", "threeLetter","numUnitedAtoms", "numFullAtomistic"]) - -#Add here new Amino acids: -Alanine=amino_acid(name="alanine", oneLetter="A", threeLetter="ALA", numUnitedAtoms=6, numFullAtomistic=None) - -Cystein=amino_acid(name="cystein", oneLetter="C", threeLetter="CYSH", numUnitedAtoms=8, numFullAtomistic=None) - -AsparticAcid=amino_acid(name="aspartic acid", oneLetter="D", threeLetter="ASP", numUnitedAtoms=9, numFullAtomistic=None) - -GlutamicAcid=amino_acid(name="glutamic acid", oneLetter="E", threeLetter="GLU", numUnitedAtoms=10, numFullAtomistic=None) - -Phenylalanine=amino_acid(name="phenylalanine", oneLetter="F", threeLetter="PHE", numUnitedAtoms=17, numFullAtomistic=None) - -Glycine=amino_acid(name="glycine", oneLetter="G", threeLetter="GLY", numUnitedAtoms=5, numFullAtomistic=None) - -Histidine_Neutral=amino_acid(name="histidine", oneLetter="H", threeLetter="HIS", numUnitedAtoms=10, numFullAtomistic=None) -Histidine_HID=amino_acid(name="histidine_HID", oneLetter="H", threeLetter="HISA", numUnitedAtoms=13, numFullAtomistic=None) -Histidine_HIE=amino_acid(name="histidine_HIE", oneLetter="H", threeLetter="HISB", numUnitedAtoms=14, numFullAtomistic=None) -Histidine_positive=amino_acid(name="histidine_positive", oneLetter="H", threeLetter="HISP", numUnitedAtoms=15, numFullAtomistic=None) - -Isoleucine=amino_acid(name="isoleucine", oneLetter="I", threeLetter="ILE", numUnitedAtoms=9, numFullAtomistic=None) - -Lysine=amino_acid(name="lysine", oneLetter="K", threeLetter="LYS", numUnitedAtoms=12, numFullAtomistic=None) -Lysine_positive=amino_acid(name="lysine_positive", oneLetter="K", threeLetter="LYSH", numUnitedAtoms=13, numFullAtomistic=None) - -Leucine=amino_acid(name="leucine", oneLetter="L", threeLetter="LEU", numUnitedAtoms=9, numFullAtomistic=None) - -Methionine=amino_acid(name="methionine", oneLetter="M", threeLetter="MET", numUnitedAtoms=9, numFullAtomistic=None) - -Asparagine=amino_acid(name="asparagine", oneLetter="N", threeLetter="ASN", numUnitedAtoms=11, numFullAtomistic=None) - -Proline=amino_acid(name="proline", oneLetter="P", threeLetter="PRO", numUnitedAtoms=7, numFullAtomistic=None) - -Glutamine=amino_acid(name="glutamine", oneLetter="Q", threeLetter="GLN", numUnitedAtoms=12, numFullAtomistic=None) - -Arginine=amino_acid(name="arginine", oneLetter="R", threeLetter="ARG", numUnitedAtoms=17, numFullAtomistic=None) - -Serine=amino_acid(name="serine", oneLetter="S", threeLetter="SER", numUnitedAtoms=8, numFullAtomistic=None) - -Threonine=amino_acid(name="threonine", oneLetter="T", threeLetter="THR", numUnitedAtoms=9, numFullAtomistic=None) - -Valine=amino_acid(name="valine", oneLetter="V", threeLetter="VAL", numUnitedAtoms=8, numFullAtomistic=None) - -Tryptophane=amino_acid(name="tryptophane", oneLetter="Y", threeLetter="TRP", numUnitedAtoms=21, numFullAtomistic=None) - -Tyrosine=amino_acid(name="tyrosine", oneLetter="Y", threeLetter="TYR", numUnitedAtoms=18, numFullAtomistic=None) - - -#Add new amino Acid into set. rest automatic -aa_set = {Alanine, Cystein, AsparticAcid, GlutamicAcid, Phenylalanine, Glycine, Histidine_Neutral, Isoleucine, Lysine, Leucine, Methionine, Asparagine, Proline, Glutamine, Arginine, Serine, Threonine, Valine, Tryptophane, Tyrosine, Lysine_positive,Histidine_HIE, Histidine_HID, Histidine_positive} - -#nici -#automatic lib gen -three_letter_aa_lib = {aa.threeLetter:aa for aa in aa_set} -one_letter_aa_lib = {aa.oneLetter:aa for aa in aa_set} -aa_lib = {aa.name:aa for aa in aa_set} \ No newline at end of file +amino_acid: namedtuple = namedtuple( + "amino_acid", ["name", "oneLetter", "threeLetter", "numUnitedAtoms", "numFullAtomistic"] +) + +# Add here new Amino acids: +Alanine = amino_acid(name="alanine", oneLetter="A", threeLetter="ALA", numUnitedAtoms=6, numFullAtomistic=None) + +Cystein = amino_acid(name="cystein", oneLetter="C", threeLetter="CYSH", numUnitedAtoms=8, numFullAtomistic=None) + +AsparticAcid = amino_acid( + name="aspartic acid", oneLetter="D", threeLetter="ASP", numUnitedAtoms=9, numFullAtomistic=None +) + +GlutamicAcid = amino_acid( + name="glutamic acid", oneLetter="E", threeLetter="GLU", numUnitedAtoms=10, numFullAtomistic=None +) + +Phenylalanine = amino_acid( + name="phenylalanine", oneLetter="F", threeLetter="PHE", numUnitedAtoms=17, numFullAtomistic=None +) + +Glycine = amino_acid(name="glycine", oneLetter="G", threeLetter="GLY", numUnitedAtoms=5, numFullAtomistic=None) + +Histidine_Neutral = amino_acid( + name="histidine", oneLetter="H", threeLetter="HIS", numUnitedAtoms=10, numFullAtomistic=None +) +Histidine_HID = amino_acid( + name="histidine_HID", oneLetter="H", threeLetter="HISA", numUnitedAtoms=13, numFullAtomistic=None +) +Histidine_HIE = amino_acid( + name="histidine_HIE", oneLetter="H", threeLetter="HISB", numUnitedAtoms=14, numFullAtomistic=None +) +Histidine_positive = amino_acid( + name="histidine_positive", oneLetter="H", threeLetter="HISP", numUnitedAtoms=15, numFullAtomistic=None +) + +Isoleucine = amino_acid(name="isoleucine", oneLetter="I", threeLetter="ILE", numUnitedAtoms=9, numFullAtomistic=None) + +Lysine = amino_acid(name="lysine", oneLetter="K", threeLetter="LYS", numUnitedAtoms=12, numFullAtomistic=None) +Lysine_positive = amino_acid( + name="lysine_positive", oneLetter="K", threeLetter="LYSH", numUnitedAtoms=13, numFullAtomistic=None +) + +Leucine = amino_acid(name="leucine", oneLetter="L", threeLetter="LEU", numUnitedAtoms=9, numFullAtomistic=None) + +Methionine = amino_acid(name="methionine", oneLetter="M", threeLetter="MET", numUnitedAtoms=9, numFullAtomistic=None) + +Asparagine = amino_acid(name="asparagine", oneLetter="N", threeLetter="ASN", numUnitedAtoms=11, numFullAtomistic=None) + +Proline = amino_acid(name="proline", oneLetter="P", threeLetter="PRO", numUnitedAtoms=7, numFullAtomistic=None) + +Glutamine = amino_acid(name="glutamine", oneLetter="Q", threeLetter="GLN", numUnitedAtoms=12, numFullAtomistic=None) + +Arginine = amino_acid(name="arginine", oneLetter="R", threeLetter="ARG", numUnitedAtoms=17, numFullAtomistic=None) + +Serine = amino_acid(name="serine", oneLetter="S", threeLetter="SER", numUnitedAtoms=8, numFullAtomistic=None) + +Threonine = amino_acid(name="threonine", oneLetter="T", threeLetter="THR", numUnitedAtoms=9, numFullAtomistic=None) + +Valine = amino_acid(name="valine", oneLetter="V", threeLetter="VAL", numUnitedAtoms=8, numFullAtomistic=None) + +Tryptophane = amino_acid(name="tryptophane", oneLetter="Y", threeLetter="TRP", numUnitedAtoms=21, numFullAtomistic=None) + +Tyrosine = amino_acid(name="tyrosine", oneLetter="Y", threeLetter="TYR", numUnitedAtoms=18, numFullAtomistic=None) + + +# Add new amino Acid into set. rest automatic +aa_set = { + Alanine, + Cystein, + AsparticAcid, + GlutamicAcid, + Phenylalanine, + Glycine, + Histidine_Neutral, + Isoleucine, + Lysine, + Leucine, + Methionine, + Asparagine, + Proline, + Glutamine, + Arginine, + Serine, + Threonine, + Valine, + Tryptophane, + Tyrosine, + Lysine_positive, + Histidine_HIE, + Histidine_HID, + Histidine_positive, +} + +# nici +# automatic lib gen +three_letter_aa_lib = {aa.threeLetter: aa for aa in aa_set} +one_letter_aa_lib = {aa.oneLetter: aa for aa in aa_set} +aa_lib = {aa.name: aa for aa in aa_set} diff --git a/pygromos/utils/bash.py b/pygromos/utils/bash.py index 1b12d9fc..adc13f19 100644 --- a/pygromos/utils/bash.py +++ b/pygromos/utils/bash.py @@ -18,7 +18,10 @@ ################################# # General functions: -def wait_for_fileSystem(check_paths: (str, List[str]), regex_mode:bool=False, max_waiting_iterations: int = 1000, verbose: bool = False) -> bool: + +def wait_for_fileSystem( + check_paths: (str, List[str]), regex_mode: bool = False, max_waiting_iterations: int = 1000, verbose: bool = False +) -> bool: """ This function can be used to circumvent lsf lag times. @@ -33,27 +36,32 @@ def wait_for_fileSystem(check_paths: (str, List[str]), regex_mode:bool=False, ma True on success """ - if(isinstance(check_paths, str)): + if isinstance(check_paths, str): check_paths = [check_paths] for check_path in check_paths: it = 0 waiting = True - while (waiting and it < max_waiting_iterations): - if(regex_mode): + while waiting and it < max_waiting_iterations: + if regex_mode: waiting = len(glob.glob(check_path)) <= 0 else: waiting = not os.path.exists(check_path) time.sleep(time_wait_s_for_filesystem) it += 1 - if (waiting): + if waiting: raise IOError("Could not find file: " + check_path) - elif (verbose): + elif verbose: print("File Check FOUND: \t", check_path) return True -def check_path_dependencies(check_required_paths: Union[Dict[any, str], List[str]], check_warn_paths: (str, List[str])=[], verbose: bool = True) -> str: + +def check_path_dependencies( + check_required_paths: Union[Dict[any, str], List[str]], + check_warn_paths: (str, List[str]) = [], + verbose: bool = True, +) -> str: """check_path_dependencies checks a list of dependencies if each path is present or not. throws an @@ -81,44 +89,56 @@ def check_path_dependencies(check_required_paths: Union[Dict[any, str], List[str found_error = False missing = [] - if (verbose and type(check_required_paths) is list): + if verbose and type(check_required_paths) is list: print("\n\n==================\n\tCHECK dependencies\n") print("\n".join(list(map(lambda s: "Check " + str(s), check_required_paths)))) - elif (verbose and type(check_required_paths) is dict): + elif verbose and type(check_required_paths) is dict: print("\nCHECK dependencies") - print("\n".join(list(map(lambda s: "Check " + str(s), [check_required_paths[x] for x in check_required_paths])))) + print( + "\n".join(list(map(lambda s: "Check " + str(s), [check_required_paths[x] for x in check_required_paths]))) + ) - #ERROR - if (type(check_required_paths) is dict): + # ERROR + if type(check_required_paths) is dict: for x in check_required_paths: - if("*" in x or "?" in x): - if(verbose): print("Skipping regex") + if "*" in x or "?" in x: + if verbose: + print("Skipping regex") continue - if verbose: print(x) - if (not isinstance(check_warn_paths[x], str) or (isinstance(check_required_paths[x], str) and not os.path.exists(check_required_paths[x]))): + if verbose: + print(x) + if not isinstance(check_warn_paths[x], str) or ( + isinstance(check_required_paths[x], str) and not os.path.exists(check_required_paths[x]) + ): found_error = True missing.append(x) - elif (type(check_required_paths) is list): + elif type(check_required_paths) is list: for x in check_required_paths: - if("*" in x or "?" in x): - if(verbose): print("Skipping regex") + if "*" in x or "?" in x: + if verbose: + print("Skipping regex") continue - if verbose: print(x) - if (not isinstance(x, str) or (isinstance(x, str) and not os.path.exists(x))): + if verbose: + print(x) + if not isinstance(x, str) or (isinstance(x, str) and not os.path.exists(x)): found_error = True missing.append(x) - #WARN - if (type(check_warn_paths) is dict): + # WARN + if type(check_warn_paths) is dict: for x in check_warn_paths: - if verbose: print(x) - if (not isinstance(check_required_paths[x], str) or (isinstance(check_required_paths[x], str) and not os.path.exists(check_required_paths[x]))): - warnings.warn("\tDid not find: "+str(x)+" with path: "+check_required_paths[x]) - elif (type(check_warn_paths) is list): + if verbose: + print(x) + if not isinstance(check_required_paths[x], str) or ( + isinstance(check_required_paths[x], str) and not os.path.exists(check_required_paths[x]) + ): + warnings.warn("\tDid not find: " + str(x) + " with path: " + check_required_paths[x]) + elif type(check_warn_paths) is list: for x in check_warn_paths: - if verbose: print(x) - if (not isinstance(x, str) or (isinstance(x, str) and not os.path.exists(x))): - warnings.warn("\tDid not find: "+str(x)) + if verbose: + print(x) + if not isinstance(x, str) or (isinstance(x, str) and not os.path.exists(x)): + warnings.warn("\tDid not find: " + str(x)) if found_error: print("\n==================\nAUTSCH\n==================\n") @@ -133,7 +153,13 @@ def check_path_dependencies(check_required_paths: Union[Dict[any, str], List[str # bash wrapper: -def extract_tar(in_path: str, out_path: str=None, gunzip_compression: bool = False, remove_tar_afterwards: bool = False, verbose: bool = False) -> str: +def extract_tar( + in_path: str, + out_path: str = None, + gunzip_compression: bool = False, + remove_tar_afterwards: bool = False, + verbose: bool = False, +) -> str: """extract_tar this wrapper helps you to unpack a tar file via the OS @@ -162,31 +188,34 @@ def extract_tar(in_path: str, out_path: str=None, gunzip_compression: bool = Fal """ option = "-" - if (gunzip_compression): + if gunzip_compression: option += "xzf" else: option += "xf" command = "tar " + option + " " + in_path - - if(isinstance(out_path, str) and in_path.replace(".tar", "").replace(".gz", "") != out_path): - command += " && mv "+in_path.replace(".tar", "").replace(".gz", "")+" "+out_path + if isinstance(out_path, str) and in_path.replace(".tar", "").replace(".gz", "") != out_path: + command += " && mv " + in_path.replace(".tar", "").replace(".gz", "") + " " + out_path else: out_path = in_path.replace(".tar", "").replace(".gz", "") - if(out_path == in_path): - raise Exception("Outpath is not allowed to be equal with in_path!\n In_path: "+in_path+"\n Out_path:"+out_path+"\n") + if out_path == in_path: + raise Exception( + "Outpath is not allowed to be equal with in_path!\n In_path: " + in_path + "\n Out_path:" + out_path + "\n" + ) - if(verbose): print("cmd: ", command) + if verbose: + print("cmd: ", command) orig_path = os.getcwd() os.chdir(os.path.dirname(in_path)) ret = execute(command, verbose=verbose) os.chdir(orig_path) - if (verbose): print("\n".join(ret.readlines())) - if (remove_tar_afterwards): - if(os.path.exists(out_path)): + if verbose: + print("\n".join(ret.readlines())) + if remove_tar_afterwards: + if os.path.exists(out_path): remove_file(in_path) wait_for_fileSystem(out_path) @@ -194,8 +223,14 @@ def extract_tar(in_path: str, out_path: str=None, gunzip_compression: bool = Fal return out_path -def compress_tar(in_path: str, out_path: str = None, gunzip_compression: bool = False, remove_in_file_afterwards: bool = False, - remove_in_dir_afterwards: bool = False, verbose: bool = False) -> str: +def compress_tar( + in_path: str, + out_path: str = None, + gunzip_compression: bool = False, + remove_in_file_afterwards: bool = False, + remove_in_dir_afterwards: bool = False, + verbose: bool = False, +) -> str: """compress_tar compress a file or directory with tar via the OS @@ -221,22 +256,21 @@ def compress_tar(in_path: str, out_path: str = None, gunzip_compression: bool = process return log. """ - - if (out_path == None): + if out_path == None: out_path = in_path - if (not out_path.endswith(".tar.gz") and gunzip_compression): + if not out_path.endswith(".tar.gz") and gunzip_compression: out_path += ".tar.gz" - elif (not out_path.endswith(".tar") and not gunzip_compression): + elif not out_path.endswith(".tar") and not gunzip_compression: out_path += ".tar" option = "-c" - if (gunzip_compression): + if gunzip_compression: option += "z" option += "f" - command = "tar " + option + " " + out_path + " " + os.path.basename(in_path)+" " + command = "tar " + option + " " + out_path + " " + os.path.basename(in_path) + " " - #command + # command orig_path = os.getcwd() os.chdir(os.path.dirname(in_path)) ret = execute(command, verbose=verbose) @@ -244,15 +278,17 @@ def compress_tar(in_path: str, out_path: str = None, gunzip_compression: bool = wait_for_fileSystem(out_path, verbose=verbose) - if(remove_in_dir_afterwards): + if remove_in_dir_afterwards: remove_file(in_path, recursive=True) - elif (remove_in_file_afterwards): + elif remove_in_file_afterwards: remove_file(in_path) return out_path -def compress_gzip(in_path: str, out_path: str = None, extract:bool=False, force:bool=True, verbose: bool = False) -> str: +def compress_gzip( + in_path: str, out_path: str = None, extract: bool = False, force: bool = True, verbose: bool = False +) -> str: """compress_gzip compress a file or directory with tar via the OS @@ -278,37 +314,37 @@ def compress_gzip(in_path: str, out_path: str = None, extract:bool=False, force: process return log. """ - - if (isinstance(out_path, type(None)) and not extract): - out_path = in_path+".gz" - elif(isinstance(out_path, type(None)) and extract): + if isinstance(out_path, type(None)) and not extract: + out_path = in_path + ".gz" + elif isinstance(out_path, type(None)) and extract: out_path = in_path.replace(".gz", "").replace(".tar", "") option = "" - if(extract): - option+= " -d " - if(force): - option+= " -f " + if extract: + option += " -d " + if force: + option += " -f " - command = "gzip " + option + " " + in_path+" " + command = "gzip " + option + " " + in_path + " " - #command + # command ret = execute(command, verbose=verbose) - if(in_path+".gz" != out_path and not extract): + if in_path + ".gz" != out_path and not extract: wait_for_fileSystem(in_path + ".gz", verbose=verbose) out_path = move_file(in_path + ".gz", out_file_path=out_path) wait_for_fileSystem(out_path, verbose=verbose) - elif(in_path != out_path+".gz" and extract): + elif in_path != out_path + ".gz" and extract: wait_for_fileSystem(in_path.replace(".gz", ""), verbose=verbose) out_path = move_file(in_path, out_file_path=out_path) wait_for_fileSystem(out_path, verbose=verbose) - return out_path -def copy_file(in_file_path: str, out_file_path: str, copy_a_directory: bool = False, additional_option: str = "") -> str: +def copy_file( + in_file_path: str, out_file_path: str, copy_a_directory: bool = False, additional_option: str = "" +) -> str: """copy_file copy files via the OS @@ -333,20 +369,27 @@ def copy_file(in_file_path: str, out_file_path: str, copy_a_directory: bool = Fa """ - if (copy_a_directory): + if copy_a_directory: additional_option += " -r " copy_files = "cp " + str(additional_option) + " " + str(in_file_path) + " " + str(out_file_path) + "\n" - if (os.system(copy_files)): - raise OSError("could not copy:\n " + str(in_file_path) + "\n \t to \n" + str(out_file_path) + "\n \t options: " + str(additional_option)) + if os.system(copy_files): + raise OSError( + "could not copy:\n " + + str(in_file_path) + + "\n \t to \n" + + str(out_file_path) + + "\n \t options: " + + str(additional_option) + ) wait_for_fileSystem(out_file_path) return out_file_path -def move_file(in_file_path: str, out_file_path: str, additional_options: str = "", verbose:bool=False) -> str: +def move_file(in_file_path: str, out_file_path: str, additional_options: str = "", verbose: bool = False) -> str: """move_file copy files via the OS @@ -371,18 +414,19 @@ def move_file(in_file_path: str, out_file_path: str, additional_options: str = " """ regex = False - if("*" in in_file_path or "?" in in_file_path): + if "*" in in_file_path or "?" in in_file_path: regex = True - elif(os.path.isfile(in_file_path) and os.path.isdir(out_file_path)): - out_file_path = os.path.dirname(out_file_path)+"/"+os.path.basename(in_file_path) + elif os.path.isfile(in_file_path) and os.path.isdir(out_file_path): + out_file_path = os.path.dirname(out_file_path) + "/" + os.path.basename(in_file_path) command = "mv " + additional_options + " " + in_file_path + " " + out_file_path + "\n" try: - ret = execute(command=command,verbose=verbose) + ret = execute(command=command, verbose=verbose) except Exception as err: - raise ValueError("BASH could not move file! "+"\n".join(map(str,err.args))) + raise ValueError("BASH could not move file! " + "\n".join(map(str, err.args))) - if(not regex): wait_for_fileSystem(out_file_path) + if not regex: + wait_for_fileSystem(out_file_path) return out_file_path @@ -410,21 +454,25 @@ def concatenate_text_files(in_file_paths: List[str], out_file_path: str, verbose None """ - if(isinstance(in_file_paths, str)): - in_file_paths = [in_file_paths] + if isinstance(in_file_paths, str): + in_file_paths = [in_file_paths] - if(isinstance(in_file_paths, str)): + if isinstance(in_file_paths, str): in_file_paths = [in_file_paths] command = "cat " + " ".join(in_file_paths) + " > " + out_file_path + " \n" - if verbose: print("CONCAT: " + command) - if (os.path.exists(os.path.dirname(out_file_path))): - if(all([os.path.exists(in_path) for in_path in in_file_paths])): - if (os.system(command)): + if verbose: + print("CONCAT: " + command) + if os.path.exists(os.path.dirname(out_file_path)): + if all([os.path.exists(in_path) for in_path in in_file_paths]): + if os.system(command): raise OSError("could not concate files:\n " + str(" ".join(in_file_paths)) + "\n to\n" + out_file_path) else: - raise IOError("could not find all in_paths!:\n " + "\n".join([ in_path for in_path in in_file_paths if(not os.path.exists(in_path))])) + raise IOError( + "could not find all in_paths!:\n " + + "\n".join([in_path for in_path in in_file_paths if (not os.path.exists(in_path))]) + ) else: raise IOError("could not find folder for:\n " + os.path.dirname(out_file_path)) @@ -432,7 +480,9 @@ def concatenate_text_files(in_file_paths: List[str], out_file_path: str, verbose return out_file_path -def replace_text_in_text_file(in_file_path: str, find_pattern: str, replace_pattern: str, out_file_path: str = None) -> str: +def replace_text_in_text_file( + in_file_path: str, find_pattern: str, replace_pattern: str, out_file_path: str = None +) -> str: """replace_text_in_text_file this file replaces a regex pattern in a text file @@ -463,7 +513,7 @@ def replace_text_in_text_file(in_file_path: str, find_pattern: str, replace_patt command = "sed s/" + find_pattern + "/" + replace_pattern + "/g " + in_file_path + " \n" out_file_path = in_file_path - if (os.system(command)): + if os.system(command): raise OSError("could not replace text in file:\n " + str(" ".join(in_file_path)) + "\n to\n" + out_file_path) wait_for_fileSystem(out_file_path) @@ -496,18 +546,18 @@ def make_folder(in_directory_path: str, additional_option: str = "", verbose: bo directory_path """ mk_folder = "mkdir " + additional_option + " " + str(in_directory_path) + "\n" - if (not os.path.isdir(in_directory_path)): - if (os.system(mk_folder)): + if not os.path.isdir(in_directory_path): + if os.system(mk_folder): raise OSError("could not make folder:\n " + str(in_directory_path)) - elif (verbose): + elif verbose: warnings.warn("WARNING:\n\t Did not build already existing folder: " + in_directory_path, category=UserWarning) wait_for_fileSystem(in_directory_path) return in_directory_path -def remove_file(in_file_path: str, recursive:bool=False, additional_options: str = "") -> None: +def remove_file(in_file_path: str, recursive: bool = False, additional_options: str = "") -> None: """remove_file delete a file via the OS. @@ -530,12 +580,14 @@ def remove_file(in_file_path: str, recursive:bool=False, additional_options: str None """ - if(recursive): - additional_options+= " -r " + if recursive: + additional_options += " -r " rm_command = "rm " + str(in_file_path) + " " + str(additional_options) - if (os.path.exists(in_file_path)): - if (os.system(rm_command)): - raise OSError("could not delete file/folder: " + str(in_file_path) + "\n options: " + str(additional_options)) + if os.path.exists(in_file_path): + if os.system(rm_command): + raise OSError( + "could not delete file/folder: " + str(in_file_path) + "\n options: " + str(additional_options) + ) def remove_folder(in_directory_path: str, additional_options: str = "", verbose: bool = False) -> None: @@ -564,11 +616,11 @@ def remove_folder(in_directory_path: str, additional_options: str = "", verbose: """ remove_folder = "rmdir " + additional_options + " " + str(in_directory_path) + "\n" - if (os.path.isdir(in_directory_path)): - if (os.system(remove_folder)): + if os.path.isdir(in_directory_path): + if os.system(remove_folder): raise OSError("could not remove folder:\n " + str(in_directory_path)) - elif (verbose): + elif verbose: warnings.warn("Warning! Did not remove non existing folder: " + in_directory_path, category=UserWarning) @@ -596,18 +648,18 @@ def save_make_folder(in_directory_path: str, additional_options: str = "") -> st offset = 1 dir_versions = list(filter(lambda x: not ".tar" in x or not ".gz" in x, sorted(glob.glob(in_directory_path + "*")))) print("dirversions:", dir_versions) - if (len(dir_versions) > 0): + if len(dir_versions) > 0: last_dir = dir_versions[len(dir_versions) - 1] print("last:", last_dir) suffix = str(last_dir.replace(in_directory_path + "_", "")) print(suffix) - if (suffix != "" and suffix.isalnum()): + if suffix != "" and suffix.isalnum(): offset = int(suffix) + 1 in_directory_path += "_" + str(offset) mk_folder = "mkdir " + additional_options + " " + str(in_directory_path) + "\n" - if (os.system(mk_folder)): + if os.system(mk_folder): raise Exception("could not make folder:\n " + str(in_directory_path)) return in_directory_path @@ -640,10 +692,16 @@ def link_folder(in_directory_path: str, out_link_path: str, additional_options: """ link_folders = "ln -s " + additional_options + " " + in_directory_path + " " + out_link_path + "\n" - if (not os.path.exists(out_link_path)): - if (os.system(link_folders)): + if not os.path.exists(out_link_path): + if os.system(link_folders): raise OSError( - "could not link:\n " + str(in_directory_path) + "\n \t to \n" + str(out_link_path) + "\n \t options: " + str(additional_options)) + "could not link:\n " + + str(in_directory_path) + + "\n \t to \n" + + str(out_link_path) + + "\n \t options: " + + str(additional_options) + ) else: raise IOError("A link with the give path already exists!: \n path:\t" + out_link_path) return out_link_path @@ -676,29 +734,39 @@ def execute_os(command: (str or List[str]), verbose: bool = False) -> io.FileIO: """ class dummyProcess: - def __init__(self, stdout, stderr, ret): self.stdout = stdout self.stderr = stderr self.poll = lambda x: int(ret) - if (type(command) == list): + if type(command) == list: command = " ".join(command) - if (verbose): print(command + "\n") + if verbose: + print(command + "\n") try: ret = os.popen(command) print(ret) except Exception as err: - raise OSError("could not execute bash command:\n error: " + "\n\t".join(err.args) + "\n\t" + str(command) + "\n\tCommand returned: \t" + str( - ret.read())) - - if (verbose): print("\t" + "\n\t".join(ret.readlines()) + "\n") + raise OSError( + "could not execute bash command:\n error: " + + "\n\t".join(err.args) + + "\n\t" + + str(command) + + "\n\tCommand returned: \t" + + str(ret.read()) + ) + + if verbose: + print("\t" + "\n\t".join(ret.readlines()) + "\n") return dummyProcess(stdout=ret, stderr=[], ret=0) -def execute_subprocess(command: (str or List[str]), catch_STD:Union[bool,str]=False, env:dict=None, verbose: bool = False)->sub.CompletedProcess: + +def execute_subprocess( + command: (str or List[str]), catch_STD: Union[bool, str] = False, env: dict = None, verbose: bool = False +) -> sub.CompletedProcess: """execute_subprocess This command starts a subprocess, that is executing the str command in bash. @@ -720,42 +788,51 @@ def execute_subprocess(command: (str or List[str]), catch_STD:Union[bool,str]=Fa return the executed process obj. (from subprocess) """ - if(isinstance(command, list)): + if isinstance(command, list): command = " ".join(command) - if(verbose): print("\texecute command: \n\t"+command) + if verbose: + print("\texecute command: \n\t" + command) - kwargs={} - if(isinstance(catch_STD, bool)): + kwargs = {} + if isinstance(catch_STD, bool): kwargs.update({"stdout": sub.PIPE}) - elif(isinstance(catch_STD, str)): + elif isinstance(catch_STD, str): kwargs.update({"stdout": open(catch_STD, "w")}) - + if env is None: - env=os.environ.copy() + env = os.environ.copy() - p = sub.Popen(args = command, shell=True, stderr=sub.PIPE, env=env, **kwargs) + p = sub.Popen(args=command, shell=True, stderr=sub.PIPE, env=env, **kwargs) - #print(p, vars(p)) - try: - p.wait(120) # Wait for process to finish + # print(p, vars(p)) + try: + p.wait(120) # Wait for process to finish except: - warnings.warn("TIME OUT WITH: "+str(command)) + warnings.warn("TIME OUT WITH: " + str(command)) print("Continue Waiting: ") - p.wait() # Wait for process to finish - p.terminate() # Make sure its terminated + p.wait() # Wait for process to finish + p.terminate() # Make sure its terminated r = p.poll() - if(r): # Did an Error occure? - msg = "SubProcess Failed due to returncode: "+str(r)+"\n COMMAND: \n\t"+str(command) + if r: # Did an Error occure? + msg = "SubProcess Failed due to returncode: " + str(r) + "\n COMMAND: \n\t" + str(command) msg += "\nSTDOUT:\n\t" - msg += "NONE" if(p.stdout is None) else "\n\t".join(map(str, p.stdout.readlines())) + msg += "NONE" if (p.stdout is None) else "\n\t".join(map(str, p.stdout.readlines())) msg += "\nSTDERR:\n\t" - msg += "NONE" if(p.stdout is None) else "\n\t".join(map(str, p.stderr.readlines())) + msg += "NONE" if (p.stdout is None) else "\n\t".join(map(str, p.stderr.readlines())) raise ChildProcessError(msg) - if(verbose): print("RETURN: ", r) + if verbose: + print("RETURN: ", r) return p -def execute_old(command: (str or List[str]), verbose: bool = False, ignore_return_code:bool=False, wait_fail=False, out_cnf_path:str=None) -> io.FileIO: + +def execute_old( + command: (str or List[str]), + verbose: bool = False, + ignore_return_code: bool = False, + wait_fail=False, + out_cnf_path: str = None, +) -> io.FileIO: """execute this command executes a command on the os-layer. (e.g.: on linux a bash command) @@ -776,28 +853,28 @@ def execute_old(command: (str or List[str]), verbose: bool = False, ignore_retur """ - if(isinstance(command, str)): + if isinstance(command, str): command = command.split() - #TODO: maybe pass path directly? + # TODO: maybe pass path directly? # This block overwrites the pipe of the sub process std_out = sub.PIPE std_err = sub.PIPE - if (verbose): print("COMMAND: "+" ".join(command) + "\n") + if verbose: + print("COMMAND: " + " ".join(command) + "\n") try: - p = sub.Popen(command, stdout=std_out, stderr=std_err) + p = sub.Popen(command, stdout=std_out, stderr=std_err) # testing this!: try: p.wait(timeout=15) except: - warnings.warn("Wait threw error!:( for cmd: "+str(command)+" If it is a long command... ok :)") + warnings.warn("Wait threw error!:( for cmd: " + str(command) + " If it is a long command... ok :)") - if(wait_fail): + if wait_fail: p.kill() - raise TimeoutError("Wait failed for proces: cmd:"+str(command)) - + raise TimeoutError("Wait failed for proces: cmd:" + str(command)) try: while p.poll() is None: @@ -808,29 +885,48 @@ def execute_old(command: (str or List[str]), verbose: bool = False, ignore_retur if verbose: print("start writing") ret_stdout = io.StringIO("".join(map(lambda x: x.decode("utf-8"), p.stdout.readlines()))) - ret_stderr ="\n".join(map(lambda x: x.decode("utf-8"), p.stderr.readlines())) + ret_stderr = "\n".join(map(lambda x: x.decode("utf-8"), p.stderr.readlines())) except TimeoutError as err: raise err except Exception as err: - raise ChildProcessError("Process failed executing Bash command:\n Command:\n\t"+ str(command) + "\n error: " + "\n\t".join(map(str, err.args)) + "\n") - - #bash command failed? - if(p.returncode > 0 and not ignore_return_code): - raise OSError("Bash command return code was Non-Zero!\nRETURN CODE: "+str(p.returncode)+"\nERR:\n"+ret_stderr+"\nstdOut:\n\t"+str("\n\t".join(ret_stdout.readlines()))+"\nCommand: "+str(command)) - - if (verbose): print("STDOUT:\n \t" + "\n\t".join(ret_stdout.readlines()) + "\n\n") - if (verbose): print("STDERR:\n \t" + ret_stderr + "\n\n") - if (verbose): print("RETURN CODE: \t" + str(p.returncode) + "\n") + raise ChildProcessError( + "Process failed executing Bash command:\n Command:\n\t" + + str(command) + + "\n error: " + + "\n\t".join(map(str, err.args)) + + "\n" + ) + + # bash command failed? + if p.returncode > 0 and not ignore_return_code: + raise OSError( + "Bash command return code was Non-Zero!\nRETURN CODE: " + + str(p.returncode) + + "\nERR:\n" + + ret_stderr + + "\nstdOut:\n\t" + + str("\n\t".join(ret_stdout.readlines())) + + "\nCommand: " + + str(command) + ) + + if verbose: + print("STDOUT:\n \t" + "\n\t".join(ret_stdout.readlines()) + "\n\n") + if verbose: + print("STDERR:\n \t" + ret_stderr + "\n\n") + if verbose: + print("RETURN CODE: \t" + str(p.returncode) + "\n") p.terminate() del p return ret_stdout -def execute(command: (str or List[str]), verbose: bool = False, catch_STD:Union[bool,str]=False, env:dict=None): + +def execute(command: (str or List[str]), verbose: bool = False, catch_STD: Union[bool, str] = False, env: dict = None): return execute_subprocess(command=command, verbose=verbose, catch_STD=catch_STD, env=env) -def which(command:str)->str: +def which(command: str) -> str: """Finds the full path of a command. Args: @@ -842,7 +938,8 @@ def which(command:str)->str: return shutil.which(command) -def command_exists(command:str)->bool: + +def command_exists(command: str) -> bool: """Does the command exists in the current system / path? Args: @@ -854,11 +951,12 @@ def command_exists(command:str)->bool: path = which(command) - if (path is None): + if path is None: return False return True -def path_exists(path:str)->bool: + +def path_exists(path: str) -> bool: """Does the provided path exists? Gives no information on whether it is a directory or a file. @@ -870,7 +968,8 @@ def path_exists(path:str)->bool: """ return os.path.exists(path) -def is_directory(path:str)->bool: + +def is_directory(path: str) -> bool: """Is the provided path a directory. Args: @@ -881,7 +980,8 @@ def is_directory(path:str)->bool: """ return os.path.isdir(path) -def is_file(path:str)->bool: + +def is_file(path: str) -> bool: """Is the provided path a file. Args: @@ -892,8 +992,9 @@ def is_file(path:str)->bool: """ return os.path.isfile(path) -def directory_exists(path:str)->bool: - """Tests whether the provided path is valid and + +def directory_exists(path: str) -> bool: + """Tests whether the provided path is valid and also is a directory. Returns false if either condition is not fullfilled. @@ -903,12 +1004,13 @@ def directory_exists(path:str)->bool: Returns: bool: Is a directory with a valid path or not. """ - if (is_directory(path) and path_exists(path)): + if is_directory(path) and path_exists(path): return True return False -def file_exists(path:str)->bool: - """Tests whether the provided path is valid and + +def file_exists(path: str) -> bool: + """Tests whether the provided path is valid and also is a file. Returns false if either condition is not fullfilled. @@ -918,7 +1020,7 @@ def file_exists(path:str)->bool: Returns: bool: Is a file with a valid path or not """ - - if (is_file(path) and path_exists(path)): + + if is_file(path) and path_exists(path): return True - return False \ No newline at end of file + return False diff --git a/pygromos/utils/pdb.py b/pygromos/utils/pdb.py index ca99c15e..7fe5f389 100644 --- a/pygromos/utils/pdb.py +++ b/pygromos/utils/pdb.py @@ -10,7 +10,8 @@ """ -def reorder_lines(header:dict, lines:list)->list: + +def reorder_lines(header: dict, lines: list) -> list: """order_dict = { # charmm_gromos54 "DPPC": { "N": 4, # Choline "C11": 1, "C14": 2, "C15": 3, "C12": 5, "C11": 6, @@ -63,120 +64,108 @@ def reorder_lines(header:dict, lines:list)->list: """ print("HO") -def rename_atom_types(lines, header, in_ff=False, out_ff=False, translation_unknown = False): - translation_dict={} + +def rename_atom_types(lines, header, in_ff=False, out_ff=False, translation_unknown=False): + translation_dict = {} charm_gromos_sel = ["gromos", "charmm"] - reverse =0 - if(type(in_ff) == bool or type(out_ff) == bool): + reverse = 0 + if type(in_ff) == bool or type(out_ff) == bool: translation_unknown = True - elif(in_ff in charm_gromos_sel and out_ff in charm_gromos_sel ): - if(in_ff in "gromos"): - reverse=1 - translation_dict = { #charmm_gromos54 - "DPPC":{ - "N": "N", #Choline - "C13":"C33", - "C14": "C34", - "C15": "C35", - "C12": "C32", - "C11": "C31", - "P": "P", #Phosphate - "O13": "O32", - "O14": "O33", - "O11": "O34", - "O12": "O31", - "C1": "C3", #Glycerol - - "C2": "C2", - "O21": "O21", - "C21": "C21", - "O22": "O22", - "C22": "C22", - - "C3": "C1", - "O31": "O11", - "C31": "C11", - "O32": "O12", - "C32": "C12", - - "C23": "C23", #Fatty acid chain1 - "C24": "C24", - "C25": "C25", - "C26": "C26", - "C27": "C27", - "C28": "C28", - "C29": "C29", - "C210": "C210", - "C211": "C211", - "C212": "C212", - "C213": "C213", - "C214": "C214", - "C215": "C215", - "C216": "C216", - - #Fatty acid chain2 - "C33": "C13", - "C34": "C14", - "C35": "C15", - "C36": "C16", - "C37": "C17", - "C38": "C18", - "C39": "C19", - "C310": "C110", - "C311": "C111", - "C312": "C112", - "C313": "C113", - "C314": "C114", - "C315": "C115", - "C316": "C116"}, - "SOLV":{ - "OH2": "OW", - "H1":"HW1", - "H2":"HW2" + elif in_ff in charm_gromos_sel and out_ff in charm_gromos_sel: + if in_ff in "gromos": + reverse = 1 + translation_dict = { # charmm_gromos54 + "DPPC": { + "N": "N", # Choline + "C13": "C33", + "C14": "C34", + "C15": "C35", + "C12": "C32", + "C11": "C31", + "P": "P", # Phosphate + "O13": "O32", + "O14": "O33", + "O11": "O34", + "O12": "O31", + "C1": "C3", # Glycerol + "C2": "C2", + "O21": "O21", + "C21": "C21", + "O22": "O22", + "C22": "C22", + "C3": "C1", + "O31": "O11", + "C31": "C11", + "O32": "O12", + "C32": "C12", + "C23": "C23", # Fatty acid chain1 + "C24": "C24", + "C25": "C25", + "C26": "C26", + "C27": "C27", + "C28": "C28", + "C29": "C29", + "C210": "C210", + "C211": "C211", + "C212": "C212", + "C213": "C213", + "C214": "C214", + "C215": "C215", + "C216": "C216", + # Fatty acid chain2 + "C33": "C13", + "C34": "C14", + "C35": "C15", + "C36": "C16", + "C37": "C17", + "C38": "C18", + "C39": "C19", + "C310": "C110", + "C311": "C111", + "C312": "C112", + "C313": "C113", + "C314": "C114", + "C315": "C115", + "C316": "C116", }, - "POT":{ #dirty HACK! - "POT": "NA" - }, - "NA":{ #dirty HACK! - "NA": "NA" - }, - "CLA":{ - "CLA": "CL" - } + "SOLV": {"OH2": "OW", "H1": "HW1", "H2": "HW2"}, + "POT": {"POT": "NA"}, # dirty HACK! + "NA": {"NA": "NA"}, # dirty HACK! + "CLA": {"CLA": "CL"}, } else: print("ops i don't know the in_ff or out_ff") - if(translation_unknown): - index=1 - resnum=0 + if translation_unknown: + index = 1 + resnum = 0 for line in lines: atom_name_index = header["atomname"] res_index = header["resname"] - if(resnum != line[header["resnum"]]): + if resnum != line[header["resnum"]]: index = 1 - resnum =line[header["resnum"]] + resnum = line[header["resnum"]] key_res = line[res_index] key = line[atom_name_index] - if (key_res == "POT"): + if key_res == "POT": line[res_index] = "NA+" - if (key_res == "CLA"): + if key_res == "CLA": line[res_index] = "CL-" - atomname = key[0]+str(index) + atomname = key[0] + str(index) line[atom_name_index] = atomname index += 1 else: - if(not reverse): + if not reverse: for line in lines: index = header["atomname"] res_index = header["resname"] key_res = line[res_index] key = line[index] - if(key_res == "POT"): + if key_res == "POT": line[res_index] = "NA+" - if(key_res == "CLA"): + if key_res == "CLA": line[res_index] = "CL-" line[index] = translation_dict[key_res][key] @@ -184,136 +173,163 @@ def rename_atom_types(lines, header, in_ff=False, out_ff=False, translation_unkn print("not implemented") return lines -def consecutivley_renumber(header: dict, lines: list)->list: + +def consecutivley_renumber(header: dict, lines: list) -> list: new_lines = [] for index, line in enumerate(lines): - #print(str(index.rst) + "line:\t"+ str(line)) - if(isinstance(line, list)): + # print(str(index.rst) + "line:\t"+ str(line)) + if isinstance(line, list): line[header["atomnum"]] = int(index) new_lines.append(line) return new_lines -def form_columns(header:dict, lines:list) -> list: - - keys=[["key", 6], ["atomnum", 5], ["BLANK", 1], ["atomname", 4], ["altLoc", 1], ["resname", 3], ["BLANK", 1], ["chain", 1], ["resnum", 3], ["insertion", 1], ["BLANK", 2], ["x", 8, 3], ["y", 8, 3], ["z",8, 3], ["occupancy", 6, 2], ["bfactor",6 ,2], ["BLANK", 7], ["segmentid", 4], ["element", 2], ["charge", 2]] - #get line format - column_string='' - index=0 +def form_columns(header: dict, lines: list) -> list: + + keys = [ + ["key", 6], + ["atomnum", 5], + ["BLANK", 1], + ["atomname", 4], + ["altLoc", 1], + ["resname", 3], + ["BLANK", 1], + ["chain", 1], + ["resnum", 3], + ["insertion", 1], + ["BLANK", 2], + ["x", 8, 3], + ["y", 8, 3], + ["z", 8, 3], + ["occupancy", 6, 2], + ["bfactor", 6, 2], + ["BLANK", 7], + ["segmentid", 4], + ["element", 2], + ["charge", 2], + ] + + # get line format + column_string = "" + index = 0 for key in keys: - if (key[0] in header): - if(len(key)==2): - if("key" == key[0]): - column_string += '{d['+str(index)+"]:<"+str(key[1])+"}" - elif("atomname" == key[0]): - column_string += '{d[' + str(index) + "]:<" + str(key[1]) + "}" + if key[0] in header: + if len(key) == 2: + if "key" == key[0]: + column_string += "{d[" + str(index) + "]:<" + str(key[1]) + "}" + elif "atomname" == key[0]: + column_string += "{d[" + str(index) + "]:<" + str(key[1]) + "}" else: - column_string += "{d["+str(index)+"]:>"+str(key[1])+"}" - elif(len(key)==3): - column_string += "{d["+str(index)+"]:>" + str(key[1]) + "."+str(key[2])+"f}" + column_string += "{d[" + str(index) + "]:>" + str(key[1]) + "}" + elif len(key) == 3: + column_string += "{d[" + str(index) + "]:>" + str(key[1]) + "." + str(key[2]) + "f}" else: raise Exception("unknown key in form_columns") index += 1 else: column_string += "".join([" " for x in range(key[1])]) - column_string +='\n' + column_string += "\n" - #format lines + # format lines new_lines = [] ##dev function for floats def isfloat(value): try: float(value) - if("." in str(value)): + if "." in str(value): return True return False except ValueError: return False for line in lines: - data = [float(value) if(isfloat(value)) else str(value) for value in line] + data = [float(value) if (isfloat(value)) else str(value) for value in line] new_line = column_string.format(d=data) new_lines.append(new_line) return new_lines -def check_ATOM_columns(lines: list) -> (dict, list) : - keys=["key", "atomnum", "atomname", "resname", "resnum", "x", "y", "z", "occupancy", "bfactor", "segmentid"] - #get sh ortest line - minimal columns - lines = [line.split() for line in lines if(line.startswith("ATOM"))] +def check_ATOM_columns(lines: list) -> (dict, list): + keys = ["key", "atomnum", "atomname", "resname", "resnum", "x", "y", "z", "occupancy", "bfactor", "segmentid"] + + # get sh ortest line - minimal columns + lines = [line.split() for line in lines if (line.startswith("ATOM"))] len_lines = list(map(lambda x: len(x), lines)) min_len = min(len_lines) - #all lines same length? - if(min_len*len(lines) != sum(len_lines)): + # all lines same length? + if min_len * len(lines) != sum(len_lines): print("Not All ATOM lines have the same length!\n taking shortest line to build header!") line = lines[len_lines.index(min_len)] offset_pointer = 0 - #check lines - add columns to standard template - if(min_len> len(keys)): #does the line have the minimal number of groups? - if(len(line[3+offset_pointer]) == 1): #is there a altloc column? + # check lines - add columns to standard template + if min_len > len(keys): # does the line have the minimal number of groups? + if len(line[3 + offset_pointer]) == 1: # is there a altloc column? keys.insert(3, "altLoc") - offset_pointer+=1 - if(line[4+offset_pointer]): #is there a chainID - keys.insert(4+offset_pointer, "chain") - offset_pointer+=1 - if(len(line[5+offset_pointer])==1):# is there an insertion column? - keys.insert(5+offset_pointer, "insertion") - - if(min_len-offset_pointer > 10): - if(str(line[10]).isdigit()): + offset_pointer += 1 + if line[4 + offset_pointer]: # is there a chainID + keys.insert(4 + offset_pointer, "chain") + offset_pointer += 1 + if len(line[5 + offset_pointer]) == 1: # is there an insertion column? + keys.insert(5 + offset_pointer, "insertion") + + if min_len - offset_pointer > 10: + if str(line[10]).isdigit(): keys.append("charge") else: keys.append("element") offset_pointer += 1 - if(min_len-offset_pointer > 11): - if(str(line[11]).isdigit()): + if min_len - offset_pointer > 11: + if str(line[11]).isdigit(): keys.append("charge") else: keys.append("element") - offset_pointer+=1 + offset_pointer += 1 - #make a dict - pdb_header = {key:ind for ind, key in enumerate(keys)} + # make a dict + pdb_header = {key: ind for ind, key in enumerate(keys)} return pdb_header, lines + def read_pdb_simple(path) -> (list, list, list): in_file = open(path, "r") lines = in_file.readlines() - header=True - footer=False + header = True + footer = False - head_lines =[] + head_lines = [] atom_lines = [] foot_lines = [] for line in lines: - if(line.startswith("ATOM")): - header=False - elif(not line.startswith("ATOM") and not header): - footer=True + if line.startswith("ATOM"): + header = False + elif not line.startswith("ATOM") and not header: + footer = True - if(header): + if header: head_lines.append(line) - elif(footer): + elif footer: foot_lines.append(line) else: atom_lines.append(line) return head_lines, atom_lines, foot_lines -def rename_atom_attribute(pattern: str, replace:str, lines: list)->list: + +def rename_atom_attribute(pattern: str, replace: str, lines: list) -> list: return [line.replace(pattern, replace) for line in lines if ("ATOM" in line)] -def filter_atoms_from_residue(filter_out:str, residue_name:str, lines:list)->(list, list): + +def filter_atoms_from_residue(filter_out: str, residue_name: str, lines: list) -> (list, list): filtered_out = list(filter(lambda x: filter_out in x and residue_name in x, lines)) - filtered_in = list(filter(lambda x: not(filter_out in x and residue_name in x), lines)) - return filtered_in, filtered_out \ No newline at end of file + filtered_in = list(filter(lambda x: not (filter_out in x and residue_name in x), lines)) + return filtered_in, filtered_out diff --git a/pygromos/utils/utils.py b/pygromos/utils/utils.py index 435627f0..52f88718 100644 --- a/pygromos/utils/utils.py +++ b/pygromos/utils/utils.py @@ -17,6 +17,7 @@ time_wait_s_for_filesystem = 0 + def _cartesian_distance(x1: float, x2: float, y1: float, y2: float, z1: float, z2: float) -> float: return math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2 + (z1 - z2) ** 2) @@ -25,15 +26,17 @@ def _cartesian_distance(x1: float, x2: float, y1: float, y2: float, z1: float, z File and submission """ + def str2bool(v): if isinstance(v, bool): return v - if v.lower() in ('yes', 'true', 't', 'y', '1'): + if v.lower() in ("yes", "true", "t", "y", "1"): return True - elif v.lower() in ('no', 'false', 'f', 'n', '0'): + elif v.lower() in ("no", "false", "f", "n", "0"): return False else: - raise argparse.ArgumentTypeError('Boolean value expected.') + raise argparse.ArgumentTypeError("Boolean value expected.") + def dynamic_parser(func: callable, title: str): """ @@ -69,10 +72,10 @@ def dynamic_parser(func: callable, title: str): default = None if (required) else args.defaults[index - total_required] if argument_type is bool: argument_type = str2bool - parser.add_argument('-' + argument, type=argument_type, required=required, default=default) + parser.add_argument("-" + argument, type=argument_type, required=required, default=default) args, unkown_args = parser.parse_known_args() - if (len(unkown_args) > 0): + if len(unkown_args) > 0: raise IOError(__name__ + " got unexpected argument(s) for parser:\n" + str(unkown_args)) return args @@ -80,8 +83,8 @@ def dynamic_parser(func: callable, title: str): def dict_to_nice_string(control_dict: Dict) -> str: """ Converts a dictionary of options (like template_control_dict) - to a more human readable format. Which can then be printed to a text file, - which can be manually modified before submiting analysis jobs. + to a more human readable format. Which can then be printed to a text file, + which can be manually modified before submiting analysis jobs. Parameters ---------- @@ -96,30 +99,30 @@ def dict_to_nice_string(control_dict: Dict) -> str: """ script_text = "control_dict = {\n" for key, value in control_dict.items(): - script_text += "\t\"" + key + "\": " + script_text += '\t"' + key + '": ' first = False - if (type(value) == dict): - if ("do" in value): # do should always be first in this list - script_text += "{\"do\":" + str(value["do"]) + "," - if (len(value) > 1): + if type(value) == dict: + if "do" in value: # do should always be first in this list + script_text += '{"do":' + str(value["do"]) + "," + if len(value) > 1: script_text += "\n" first = True for key2, value2 in value.items(): # alternative keys # prefix - if (first): + if first: prefix = " " first = False else: prefix = "\t\t" # key_val - if (key2 == "do"): + if key2 == "do": continue - elif (type(value2) == dict): - script_text += prefix + "\"" + str(key2) + "\": " + _inline_dict(value2, "\t\t\t") + ",\n" + elif type(value2) == dict: + script_text += prefix + '"' + str(key2) + '": ' + _inline_dict(value2, "\t\t\t") + ",\n" else: - script_text += prefix + "\"" + str(key2) + "\": " + str(value2) + "," + script_text += prefix + '"' + str(key2) + '": ' + str(value2) + "," script_text += prefix + " },\n" else: script_text += str(value) + ",\n" @@ -146,15 +149,20 @@ def _inline_dict(in_dict: Dict, prefix: str = "\t") -> str: """ msg = "{\n" for key, value in in_dict.items(): - if (type(value) == dict): - msg += prefix + "\"" + str(key) + "\": " + _inline_dict(in_dict=value, prefix=prefix + "\t") + "," + if type(value) == dict: + msg += prefix + '"' + str(key) + '": ' + _inline_dict(in_dict=value, prefix=prefix + "\t") + "," else: - msg += prefix + "\"" + str(key) + "\": " + str(value) + ",\n" + msg += prefix + '"' + str(key) + '": ' + str(value) + ",\n" return msg + prefix + "}" -def write_job_script(out_script_path: str, target_function: callable, variable_dict: dict, python_cmd: str = "python3", - verbose: bool = False) -> str: +def write_job_script( + out_script_path: str, + target_function: callable, + variable_dict: dict, + python_cmd: str = "python3", + verbose: bool = False, +) -> str: """ this function writes submission commands into a file. The command will be started from a bash env into python. @@ -185,16 +193,18 @@ def write_job_script(out_script_path: str, target_function: callable, variable_d if required variable from the var-dict for the function is missing """ - if (not os.path.exists(os.path.dirname(out_script_path))): + if not os.path.exists(os.path.dirname(out_script_path)): raise IOError( - "Could not find path of dir, that should contain the schedule script!\n\t Got Path: " + out_script_path) + "Could not find path of dir, that should contain the schedule script!\n\t Got Path: " + out_script_path + ) import pygromos + # Build str: s = inspect.signature(target_function) # to lazy for numpydoc - import_string = "" + import_string = "" import_string += "#IMPORTS\n" import_string += "import sys\n" - import_string += "sys.path.append(\""+os.path.abspath(os.path.dirname(pygromos.__file__)+"/..")+"\")\n" + import_string += 'sys.path.append("' + os.path.abspath(os.path.dirname(pygromos.__file__) + "/..") + '")\n' import_string += "from " + str(target_function.__module__) + " import " + target_function.__name__ vars_string = "#VARIABLES: \n" cmd_options = "" @@ -204,39 +214,45 @@ def write_job_script(out_script_path: str, target_function: callable, variable_d missed_keys = [] for key in s.parameters: - if (key in variable_dict): + if key in variable_dict: value = variable_dict[key] - if (isinstance(value, Gromos_System) or issubclass(value.__class__, _SubmissionSystem)): # this is a nasty way! ... tends to fail! + if isinstance(value, Gromos_System) or issubclass( + value.__class__, _SubmissionSystem + ): # this is a nasty way! ... tends to fail! sys = value vars_string += sys.get_script_generation_command(var_name=key) - elif (isinstance(value, Dict)): + elif isinstance(value, Dict): vars_string += dict_to_nice_string(value) - elif (isinstance(value, List)): + elif isinstance(value, List): vars_string += key + "= [ " + ", ".join(map(str, value)) + "]\n" - elif (isinstance(value, str)): - vars_string += key + " = \"" + str(value) + "\"\n" + elif isinstance(value, str): + vars_string += key + ' = "' + str(value) + '"\n' else: vars_string += key + " = " + str(value) + "\n" cmd_options += key + "=" + key + ", " - elif (s.parameters[key].default == inspect._empty): + elif s.parameters[key].default == inspect._empty: missed_keys.append(key) - if (len(missed_keys) > 0): + if len(missed_keys) > 0: raise ValueError( - "Found some variables missing in variable dict,that are required!\n\t" + "\n\t".join(missed_keys)) + "Found some variables missing in variable dict,that are required!\n\t" + "\n\t".join(missed_keys) + ) cmd_string = "\n#DO\n" cmd_string += target_function.__name__ + "(" + cmd_options + ")" cmd_string += "\nexit(0)\n\n" - script_text = "#!/usr/bin/env " + python_cmd + "\n\n" + import_string + "\n\n" + vars_string + "\n\n" + cmd_string + "\n" - if (verbose): print(script_text) + script_text = ( + "#!/usr/bin/env " + python_cmd + "\n\n" + import_string + "\n\n" + vars_string + "\n\n" + cmd_string + "\n" + ) + if verbose: + print(script_text) # write out file out_script_file = open(out_script_path, "w") out_script_file.write(script_text) out_script_file.close() - os.system("chmod +x "+out_script_path) + os.system("chmod +x " + out_script_path) return out_script_path diff --git a/pygromos/visualization/coordinates_visualization.py b/pygromos/visualization/coordinates_visualization.py index f63867a7..1611c8f8 100644 --- a/pygromos/visualization/coordinates_visualization.py +++ b/pygromos/visualization/coordinates_visualization.py @@ -7,17 +7,18 @@ from copy import deepcopy import py3Dmol + def show_cnf(cnf: Cnf): cCNF = deepcopy(cnf) - view=py3Dmol.view(width=400, height=400) + view = py3Dmol.view(width=400, height=400) - solute = [resn[:3] for resn in cnf.residues if(resn !="SOLV")] - if(len([res for res in solute if(res in three_letter_aa_lib)])>15 or "SOLV" in cnf.residues): + solute = [resn[:3] for resn in cnf.residues if (resn != "SOLV")] + if len([res for res in solute if (res in three_letter_aa_lib)]) > 15 or "SOLV" in cnf.residues: pos = [] for atomP in cCNF.POSITION: atomP.atomType = atomP.atomType[:1] - if(atomP.resName == "SOLV"): + if atomP.resName == "SOLV": pos.append(atomP) solv_cnf = deepcopy(cnf) solv_cnf.POSITION = pos @@ -28,15 +29,15 @@ def show_cnf(cnf: Cnf): view.addModel(xyz_str) view.addModel(xyzd_str) - view.setStyle({'resn': solute}, {"stick": {}}) + view.setStyle({"resn": solute}, {"stick": {}}) - if(len([res for res in solute if(res in three_letter_aa_lib)])>15): - protein = [res for res in solute if(res in three_letter_aa_lib)] - view.setStyle({'resn': protein}, {"cartoon": {}}) - view.setStyle({'cartoon': {'arrows': True, 'tubes': True, 'style': 'oval'}}) + if len([res for res in solute if (res in three_letter_aa_lib)]) > 15: + protein = [res for res in solute if (res in three_letter_aa_lib)] + view.setStyle({"resn": protein}, {"cartoon": {}}) + view.setStyle({"cartoon": {"arrows": True, "tubes": True, "style": "oval"}}) - view.setStyle({'resn': "SOLV"}, {"line": {}}) # Solvent - view.setStyle({'resn': ions}, {"sphere": {"color": "lightgreen", "radius":0.7}}) # ions + view.setStyle({"resn": "SOLV"}, {"line": {}}) # Solvent + view.setStyle({"resn": ions}, {"sphere": {"color": "lightgreen", "radius": 0.7}}) # ions else: xyz_str = cCNF.get_xyz() @@ -47,8 +48,7 @@ def show_cnf(cnf: Cnf): return view - -def show_coordinate_traj(trc:Trc, cnf: Cnf): +def show_coordinate_traj(trc: Trc, cnf: Cnf): """ This function visualizes the provided TRC and maps it on the @@ -65,15 +65,15 @@ def show_coordinate_traj(trc:Trc, cnf: Cnf): traj = trc.get_pdb(cnf) view = py3Dmol.view(width=400, height=400) view.addModelsAsFrames(traj) - view.setStyle({'model': -1}, {"stick": {}}) + view.setStyle({"model": -1}, {"stick": {}}) - solute = [resn[:3] for resn in cnf.residues if(resn !="SOLV")] + solute = [resn[:3] for resn in cnf.residues if (resn != "SOLV")] aminoA = [res for res in solute if (res in three_letter_aa_lib)] - if (len(aminoA) > 15): - view.setStyle({'resn': aminoA}, {"cartoon": {'arrows': True, 'tubes': True, 'style': 'oval'}}) - view.setStyle({'resn': ions}, {"sphere": {"color": "lightgreen", "radius": 0.7}}) # ions + if len(aminoA) > 15: + view.setStyle({"resn": aminoA}, {"cartoon": {"arrows": True, "tubes": True, "style": "oval"}}) + view.setStyle({"resn": ions}, {"sphere": {"color": "lightgreen", "radius": 0.7}}) # ions - view.animate({"loop":"forward", "reps":1}) + view.animate({"loop": "forward", "reps": 1}) view.zoomTo() return view diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 5c57f58b..00000000 --- a/requirements.txt +++ /dev/null @@ -1,17 +0,0 @@ -# This file may be used to create an environment using: -# $ conda create --name --file -# platform: linux-64 -numpy>=1.19.1 -pandas>=1.1.2 -scipy>=1.5.2 -sympy>=1.6.2 -matplotlib -rdkit -mpmath - -jupyter>=1.0.0 -typing>=3.7.4.3 - -sphinx>=3.2.1 -nbsphinx>=0.7.1 -m2r>=0.2.1 diff --git a/setup.py b/setup.py index 89af29e4..8853791c 100644 --- a/setup.py +++ b/setup.py @@ -9,8 +9,8 @@ short_description = __doc__.split("\n") # from https://github.com/pytest-dev/pytest-runner#conditional-requirement -needs_pytest = {'pytest', 'test', 'ptr'}.intersection(sys.argv) -pytest_runner = ['pytest-runner'] if needs_pytest else [] +needs_pytest = {"pytest", "test", "ptr"}.intersection(sys.argv) +pytest_runner = ["pytest-runner"] if needs_pytest else [] try: with open("README.md", "r") as handle: @@ -21,39 +21,33 @@ setup( # Self-descriptive entries which should always be present - name='PyGromos', - author='Benjamin J. Ries, Marc Lehner, Salome Rieder', - author_email='bschroed@ethz.ch', + name="PyGromos", + author="Benjamin J. Ries, Marc Lehner, Salome Rieder", + author_email="bschroed@ethz.ch", description=short_description[0], long_description=long_description, long_description_content_type="text/markdown", version=versioneer.get_version(), cmdclass=versioneer.get_cmdclass(), - license='MIT', - + license="MIT", # Which Python importable modules should be included when your package is installed # Handled automatically by setuptools. Use 'exclude' to prevent some specific # subpackage(s) from being added, if needed packages=find_packages(), - # Optional include package data to ship with your package # Customize MANIFEST.in if the general case does not suit your needs # Comment out this line to prevent the files from being packaged with your software include_package_data=True, - # Allows `setup.py dev` to work correctly with pytest setup_requires=[] + pytest_runner, - # Additional entries you may want simply uncomment the lines you want and fill in the data # url='http://www.my_package.com', # Website - #install_requires=["rdkit"], # Required packages, pulls from pip if needed; do not use for Conda deployment + # install_requires=["rdkit"], # Required packages, pulls from pip if needed; do not use for Conda deployment # platforms=['Linux', # 'Mac OS-X', # 'Unix', # 'Windows'], # Valid platforms your code works on, adjust to your flavor - python_requires=">=3.5", # Python version restrictions - + python_requires=">=3.5", # Python version restrictions # Manual control if final package is compressible or not, set False to prevent the .egg from being made # zip_safe=False, - ) diff --git a/styleguide.md b/styleguide.md new file mode 100644 index 00000000..4797cf36 --- /dev/null +++ b/styleguide.md @@ -0,0 +1,17 @@ +# Style Guide for PyGromosTools + +## Introduction + +This file contains the style guide for PyGromosTools. All code should be written according to this style guide. PRs that violate this style guide will be automatically rejected. + +WIP: This style guide is still in development. Please be patient and report any issues you find. Thank you! + +## Python style guide in short + +The most important points in short: + +1. Clear and descriptive variable names +2. Good docstrings (numpy style) +3. Adhere to PEP8 style guidelines +4. Adhere to the google style guide () +5. Check your code against pylint and pre-commit hooks (described in pre-commit-config.yaml) diff --git a/versioneer.py b/versioneer.py index 64fea1c8..a1eca36d 100644 --- a/versioneer.py +++ b/versioneer.py @@ -1,4 +1,3 @@ - # Version: 0.18 """The Versioneer - like a rocketeer, but for versions. @@ -277,6 +276,7 @@ """ from __future__ import print_function + try: import configparser except ImportError: @@ -308,11 +308,13 @@ def get_root(): setup_py = os.path.join(root, "setup.py") versioneer_py = os.path.join(root, "versioneer.py") if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)): - err = ("Versioneer was unable to run the project root directory. " - "Versioneer requires setup.py to be executed from " - "its immediate directory (like 'python setup.py COMMAND'), " - "or in a way that lets it use sys.argv[0] to find the root " - "(like 'python path/to/setup.py COMMAND').") + err = ( + "Versioneer was unable to run the project root directory. " + "Versioneer requires setup.py to be executed from " + "its immediate directory (like 'python setup.py COMMAND'), " + "or in a way that lets it use sys.argv[0] to find the root " + "(like 'python path/to/setup.py COMMAND')." + ) raise VersioneerBadRootError(err) try: # Certain runtime workflows (setup.py install/develop in a setuptools @@ -325,8 +327,7 @@ def get_root(): me_dir = os.path.normcase(os.path.splitext(me)[0]) vsr_dir = os.path.normcase(os.path.splitext(versioneer_py)[0]) if me_dir != vsr_dir: - print("Warning: build in %s is using versioneer.py from %s" - % (os.path.dirname(me), versioneer_py)) + print("Warning: build in %s is using versioneer.py from %s" % (os.path.dirname(me), versioneer_py)) except NameError: pass return root @@ -348,6 +349,7 @@ def get(parser, name): if parser.has_option("versioneer", name): return parser.get("versioneer", name) return None + cfg = VersioneerConfig() cfg.VCS = VCS cfg.style = get(parser, "style") or "" @@ -372,17 +374,18 @@ class NotThisMethod(Exception): def register_vcs_handler(vcs, method): # decorator """Decorator to mark a method as the handler for a particular VCS.""" + def decorate(f): """Store f in HANDLERS[vcs][method].""" if vcs not in HANDLERS: HANDLERS[vcs] = {} HANDLERS[vcs][method] = f return f + return decorate -def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, - env=None): +def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, env=None): """Call the given command(s).""" assert isinstance(commands, list) p = None @@ -390,10 +393,9 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, try: dispcmd = str([c] + args) # remember shell=False, so use git.cmd on windows, not just git - p = subprocess.Popen([c] + args, cwd=cwd, env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr - else None)) + p = subprocess.Popen( + [c] + args, cwd=cwd, env=env, stdout=subprocess.PIPE, stderr=(subprocess.PIPE if hide_stderr else None) + ) break except EnvironmentError: e = sys.exc_info()[1] @@ -418,7 +420,9 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, return stdout, p.returncode -LONG_VERSION_PY['git'] = ''' +LONG_VERSION_PY[ + "git" +] = ''' # This file helps to compute a version number in source trees obtained from # git-archive tarball (such as those provided by githubs download-from-tag # feature). Distribution tarballs (built by setup.py sdist) and build @@ -993,7 +997,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of # just "foo-1.0". If we see a "tag: " prefix, prefer those. TAG = "tag: " - tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) + tags = set([r[len(TAG) :] for r in refs if r.startswith(TAG)]) if not tags: # Either we're using git < 1.8.3, or there really are no tags. We use # a heuristic: assume all version tags have a digit. The old git %d @@ -1002,7 +1006,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # between branches and tags. By ignoring refnames without digits, we # filter out many common branch names like "release" and # "stabilization", as well as "HEAD" and "master". - tags = set([r for r in refs if re.search(r'\d', r)]) + tags = set([r for r in refs if re.search(r"\d", r)]) if verbose: print("discarding '%s', no digits" % ",".join(refs - tags)) if verbose: @@ -1010,19 +1014,26 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): for ref in sorted(tags): # sorting will prefer e.g. "2.0" over "2.0rc1" if ref.startswith(tag_prefix): - r = ref[len(tag_prefix):] + r = ref[len(tag_prefix) :] if verbose: print("picking %s" % r) - return {"version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": None, - "date": date} + return { + "version": r, + "full-revisionid": keywords["full"].strip(), + "dirty": False, + "error": None, + "date": date, + } # no suitable tags, so version is "0+unknown", but full hex is still there if verbose: print("no suitable tags, using unknown + full revision id") - return {"version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": "no suitable tags", "date": None} + return { + "version": "0+unknown", + "full-revisionid": keywords["full"].strip(), + "dirty": False, + "error": "no suitable tags", + "date": None, + } @register_vcs_handler("git", "pieces_from_vcs") @@ -1037,8 +1048,7 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] - out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, - hide_stderr=True) + out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True) if rc != 0: if verbose: print("Directory %s not under git control" % root) @@ -1046,10 +1056,9 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", - "--always", "--long", - "--match", "%s*" % tag_prefix], - cwd=root) + describe_out, rc = run_command( + GITS, ["describe", "--tags", "--dirty", "--always", "--long", "--match", "%s*" % tag_prefix], cwd=root + ) # --long was added in git-1.5.5 if describe_out is None: raise NotThisMethod("'git describe' failed") @@ -1072,17 +1081,16 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): dirty = git_describe.endswith("-dirty") pieces["dirty"] = dirty if dirty: - git_describe = git_describe[:git_describe.rindex("-dirty")] + git_describe = git_describe[: git_describe.rindex("-dirty")] # now we have TAG-NUM-gHEX or HEX if "-" in git_describe: # TAG-NUM-gHEX - mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) + mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe) if not mo: # unparseable. Maybe git-describe is misbehaving? - pieces["error"] = ("unable to parse git-describe output: '%s'" - % describe_out) + pieces["error"] = "unable to parse git-describe output: '%s'" % describe_out return pieces # tag @@ -1091,10 +1099,9 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if verbose: fmt = "tag '%s' doesn't start with prefix '%s'" print(fmt % (full_tag, tag_prefix)) - pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" - % (full_tag, tag_prefix)) + pieces["error"] = "tag '%s' doesn't start with prefix '%s'" % (full_tag, tag_prefix) return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix):] + pieces["closest-tag"] = full_tag[len(tag_prefix) :] # distance: number of commits since tag pieces["distance"] = int(mo.group(2)) @@ -1105,13 +1112,11 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): else: # HEX: no tags pieces["closest-tag"] = None - count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], - cwd=root) + count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], cwd=root) pieces["distance"] = int(count_out) # total number of commits # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], - cwd=root)[0].strip() + date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[0].strip() pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) return pieces @@ -1167,16 +1172,19 @@ def versions_from_parentdir(parentdir_prefix, root, verbose): for i in range(3): dirname = os.path.basename(root) if dirname.startswith(parentdir_prefix): - return {"version": dirname[len(parentdir_prefix):], - "full-revisionid": None, - "dirty": False, "error": None, "date": None} + return { + "version": dirname[len(parentdir_prefix) :], + "full-revisionid": None, + "dirty": False, + "error": None, + "date": None, + } else: rootdirs.append(root) root = os.path.dirname(root) # up a level if verbose: - print("Tried directories %s but none started with prefix %s" % - (str(rootdirs), parentdir_prefix)) + print("Tried directories %s but none started with prefix %s" % (str(rootdirs), parentdir_prefix)) raise NotThisMethod("rootdir doesn't start with parentdir_prefix") @@ -1205,11 +1213,9 @@ def versions_from_file(filename): contents = f.read() except EnvironmentError: raise NotThisMethod("unable to read _version.py") - mo = re.search(r"version_json = '''\n(.*)''' # END VERSION_JSON", - contents, re.M | re.S) + mo = re.search(r"version_json = '''\n(.*)''' # END VERSION_JSON", contents, re.M | re.S) if not mo: - mo = re.search(r"version_json = '''\r\n(.*)''' # END VERSION_JSON", - contents, re.M | re.S) + mo = re.search(r"version_json = '''\r\n(.*)''' # END VERSION_JSON", contents, re.M | re.S) if not mo: raise NotThisMethod("no version_json in _version.py") return json.loads(mo.group(1)) @@ -1218,8 +1224,7 @@ def versions_from_file(filename): def write_to_version_file(filename, versions): """Write the given version number to the given _version.py file.""" os.unlink(filename) - contents = json.dumps(versions, sort_keys=True, - indent=1, separators=(",", ": ")) + contents = json.dumps(versions, sort_keys=True, indent=1, separators=(",", ": ")) with open(filename, "w") as f: f.write(SHORT_VERSION_PY % contents) @@ -1251,8 +1256,7 @@ def render_pep440(pieces): rendered += ".dirty" else: # exception #1 - rendered = "0+untagged.%d.g%s" % (pieces["distance"], - pieces["short"]) + rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered @@ -1366,11 +1370,13 @@ def render_git_describe_long(pieces): def render(pieces, style): """Render the given version pieces into the requested style.""" if pieces["error"]: - return {"version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None} + return { + "version": "unknown", + "full-revisionid": pieces.get("long"), + "dirty": None, + "error": pieces["error"], + "date": None, + } if not style or style == "default": style = "pep440" # the default @@ -1390,9 +1396,13 @@ def render(pieces, style): else: raise ValueError("unknown style '%s'" % style) - return {"version": rendered, "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], "error": None, - "date": pieces.get("date")} + return { + "version": rendered, + "full-revisionid": pieces["long"], + "dirty": pieces["dirty"], + "error": None, + "date": pieces.get("date"), + } class VersioneerBadRootError(Exception): @@ -1415,8 +1425,7 @@ def get_versions(verbose=False): handlers = HANDLERS.get(cfg.VCS) assert handlers, "unrecognized VCS '%s'" % cfg.VCS verbose = verbose or cfg.verbose - assert cfg.versionfile_source is not None, \ - "please set versioneer.versionfile_source" + assert cfg.versionfile_source is not None, "please set versioneer.versionfile_source" assert cfg.tag_prefix is not None, "please set versioneer.tag_prefix" versionfile_abs = os.path.join(root, cfg.versionfile_source) @@ -1470,9 +1479,13 @@ def get_versions(verbose=False): if verbose: print("unable to compute version") - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, "error": "unable to compute version", - "date": None} + return { + "version": "0+unknown", + "full-revisionid": None, + "dirty": None, + "error": "unable to compute version", + "date": None, + } def get_version(): @@ -1521,6 +1534,7 @@ def run(self): print(" date: %s" % vers.get("date")) if vers["error"]: print(" error: %s" % vers["error"]) + cmds["version"] = cmd_version # we override "build_py" in both distutils and setuptools @@ -1553,14 +1567,15 @@ def run(self): # now locate _version.py in the new build/ directory and replace # it with an updated value if cfg.versionfile_build: - target_versionfile = os.path.join(self.build_lib, - cfg.versionfile_build) + target_versionfile = os.path.join(self.build_lib, cfg.versionfile_build) print("UPDATING %s" % target_versionfile) write_to_version_file(target_versionfile, versions) + cmds["build_py"] = cmd_build_py if "cx_Freeze" in sys.modules: # cx_freeze enabled? from cx_Freeze.dist import build_exe as _build_exe + # nczeczulin reports that py2exe won't like the pep440-style string # as FILEVERSION, but it can be used for PRODUCTVERSION, e.g. # setup(console=[{ @@ -1581,17 +1596,21 @@ def run(self): os.unlink(target_versionfile) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % - {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) + f.write( + LONG + % { + "DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + } + ) + cmds["build_exe"] = cmd_build_exe del cmds["build_py"] - if 'py2exe' in sys.modules: # py2exe enabled? + if "py2exe" in sys.modules: # py2exe enabled? try: from py2exe.distutils_buildexe import py2exe as _py2exe # py3 except ImportError: @@ -1610,13 +1629,17 @@ def run(self): os.unlink(target_versionfile) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % - {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) + f.write( + LONG + % { + "DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + } + ) + cmds["py2exe"] = cmd_py2exe # we override different "sdist" commands for both environments @@ -1643,8 +1666,8 @@ def make_release_tree(self, base_dir, files): # updated value target_versionfile = os.path.join(base_dir, cfg.versionfile_source) print("UPDATING %s" % target_versionfile) - write_to_version_file(target_versionfile, - self._versioneer_generated_versions) + write_to_version_file(target_versionfile, self._versioneer_generated_versions) + cmds["sdist"] = cmd_sdist return cmds @@ -1699,11 +1722,9 @@ def do_setup(): root = get_root() try: cfg = get_config_from_root(root) - except (EnvironmentError, configparser.NoSectionError, - configparser.NoOptionError) as e: + except (EnvironmentError, configparser.NoSectionError, configparser.NoOptionError) as e: if isinstance(e, (EnvironmentError, configparser.NoSectionError)): - print("Adding sample versioneer config to setup.cfg", - file=sys.stderr) + print("Adding sample versioneer config to setup.cfg", file=sys.stderr) with open(os.path.join(root, "setup.cfg"), "a") as f: f.write(SAMPLE_CONFIG) print(CONFIG_ERROR, file=sys.stderr) @@ -1712,15 +1733,18 @@ def do_setup(): print(" creating %s" % cfg.versionfile_source) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) - - ipy = os.path.join(os.path.dirname(cfg.versionfile_source), - "__init__.py") + f.write( + LONG + % { + "DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + } + ) + + ipy = os.path.join(os.path.dirname(cfg.versionfile_source), "__init__.py") if os.path.exists(ipy): try: with open(ipy, "r") as f: @@ -1762,8 +1786,7 @@ def do_setup(): else: print(" 'versioneer.py' already in MANIFEST.in") if cfg.versionfile_source not in simple_includes: - print(" appending versionfile_source ('%s') to MANIFEST.in" % - cfg.versionfile_source) + print(" appending versionfile_source ('%s') to MANIFEST.in" % cfg.versionfile_source) with open(manifest_in, "a") as f: f.write("include %s\n" % cfg.versionfile_source) else: