├── .bumpversion.toml ├── .github ├── ISSUE_TEMPLATE │ ├── BUG_REPORT.md │ ├── FEATURE_REQUEST.md │ └── QUESTION.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── CI.yaml │ └── codeql.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .readthedocs.yml ├── CHANGELOG.md ├── CITATION.cff ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE.rst ├── MANIFEST.in ├── README.md ├── codecov.yml ├── devtools ├── README.md └── docker-entrypoint.sh ├── docs ├── Makefile ├── _templates │ └── footer.html ├── conf.py ├── docs-env.yml ├── files │ ├── mbuild_citation.bib │ └── mbuild_citation.ris ├── getting_started │ ├── example_system.rst │ ├── installation │ │ ├── docker.rst │ │ ├── installation.rst │ │ └── installation_toc.rst │ ├── quick_start │ │ ├── Box_example.rst │ │ ├── fill_box_example.rst │ │ ├── load_files.rst │ │ ├── polymer_example.rst │ │ └── quick_start.rst │ ├── tutorials │ │ ├── ch3.pdb │ │ ├── custom.css │ │ ├── ethane.mol2 │ │ ├── generate_html.sh │ │ ├── methane.mol2 │ │ ├── tutorial_ethane.rst │ │ ├── tutorial_lattice.rst │ │ ├── tutorial_methane.rst │ │ ├── tutorial_monolayer.rst │ │ ├── tutorial_polymers.rst │ │ ├── tutorial_simple_LJ.rst │ │ └── tutorials.rst │ └── writers │ │ ├── cassandra_file_writers.rst │ │ └── writers.rst ├── images │ ├── data_structures.png │ ├── lattice_BCC_CsCl_image.png │ ├── lattice_Diamond_cubic_Si_image.png │ ├── lattice_FCC_Cu_image.png │ ├── lattice_SC_polonium_image.png │ ├── lattice_graphene_2D_image.png │ ├── mosdef_mbuild.svg │ ├── pmpc.png │ ├── polymer_example_image.png │ ├── polymer_image.png │ ├── tnp.png │ └── tnp_box.png ├── index.rst ├── make.bat ├── reference │ ├── citing_mbuild.rst │ ├── older_documentation.rst │ └── units.rst ├── sphinxext │ ├── embed.tpl │ └── notebook_sphinxext.py └── topic_guides │ ├── coordinate_transforms.rst │ ├── data_structures.rst │ ├── load_data.rst │ ├── recipe_development.rst │ └── recipes.rst ├── environment-dev.yml ├── environment.yml ├── mbuild ├── __init__.py ├── bond_graph.py ├── box.py ├── coarse_graining.py ├── compound.py ├── conversion.py ├── coordinate_transform.py ├── exceptions.py ├── formats │ ├── README.txt │ ├── __init__.py │ ├── cassandramcf.py │ ├── compound.proto │ ├── json_formats.py │ └── vasp.py ├── lattice.py ├── lib │ ├── __init__.py │ ├── atoms │ │ ├── __init__.py │ │ ├── c3.py │ │ ├── h.py │ │ └── n4.py │ ├── bulk_materials │ │ ├── __init__.py │ │ ├── amorphous_silica_bulk.pdb │ │ └── amorphous_silica_bulk.py │ ├── moieties │ │ ├── __init__.py │ │ ├── ch2.pdb │ │ ├── ch2.py │ │ ├── ch3.pdb │ │ ├── ch3.py │ │ ├── ester.pdb │ │ ├── ester.py │ │ ├── h2o.py │ │ ├── peg.py │ │ ├── peg_monomer.pdb │ │ ├── silane.pdb │ │ └── silane.py │ ├── molecules │ │ ├── __init__.py │ │ ├── ethane.py │ │ ├── methane.py │ │ └── water.py │ ├── recipes │ │ ├── __init__.py │ │ ├── alkane.py │ │ ├── monolayer.py │ │ ├── polymer.py │ │ ├── silica_interface.py │ │ ├── tiled_compound.py │ │ ├── water_box.py │ │ └── water_proto.gro │ └── surfaces │ │ ├── __init__.py │ │ ├── amorphous_silica_sr1.0.pdb │ │ ├── amorphous_silica_surface.py │ │ ├── beta-cristobalite-expanded.mol2 │ │ └── betacristobalite.py ├── packing.py ├── pattern.py ├── periodic_kdtree.py ├── port.py ├── recipes │ └── __init__.py ├── tests │ ├── __init__.py │ ├── base_test.py │ ├── test_box.py │ ├── test_cif.py │ ├── test_coarse_graining.py │ ├── test_compound.py │ ├── test_coordinate_transform.py │ ├── test_gmso.py │ ├── test_json_formats.py │ ├── test_lattice.py │ ├── test_lib_molecule.py │ ├── test_mol2file.py │ ├── test_monolayer.py │ ├── test_packing.py │ ├── test_pattern.py │ ├── test_plugins.py │ ├── test_polymer.py │ ├── test_port.py │ ├── test_silica_interface.py │ ├── test_silica_surface.py │ ├── test_tiled_compound.py │ ├── test_utils.py │ ├── test_vasp.py │ └── test_water_box.py └── utils │ ├── __init__.py │ ├── conversion.py │ ├── decorators.py │ ├── exceptions.py │ ├── geometry.py │ ├── io.py │ ├── jsutils.py │ ├── orderedset.py │ ├── reference │ ├── 6m03.pdb │ ├── Charmm_writer_testing_only_zeolite.xml │ ├── ETV_triclinic.cif │ ├── ITG_monoclinic.cif │ ├── LaCl3.cif │ ├── ReS2.cif │ ├── benzene-nonatom-nonelement.mol2 │ ├── benzene-nonelement.mol2 │ ├── benzene.mol2 │ ├── beta-cristobalite-expanded.mol2 │ ├── cg-chol.pdb │ ├── ch.mol2 │ ├── charmm36_cooh.xml │ ├── charmm_dihedral.mol2 │ ├── charmm_truncated.xml │ ├── charmm_truncated_singleterm.xml │ ├── cholesterol.pdb │ ├── cholesterol.sdf │ ├── decane.xyz │ ├── ecer2.pdb │ ├── ethane.xyz │ ├── extra_blank_field.cif │ ├── gaff_test.xml │ ├── lj.xml │ ├── methane_oplssaa.xml │ ├── methyl.mol2 │ ├── methyl.pdb │ ├── needs_to_be_wrapped.cif │ ├── p3ht.smi │ ├── pro_but.pdb │ ├── restart.gsd │ ├── small_oplsaa.xml │ ├── spc.pdb │ ├── styrene.mol2 │ ├── tip3p_water.xyz │ ├── too_few_atoms.xyz │ └── too_many_atoms.xyz │ ├── sorting.py │ └── validation.py ├── pyproject.toml └── setup.cfg /.bumpversion.toml: -------------------------------------------------------------------------------- 1 | [tool.bumpversion] 2 | current_version = "1.1.1" 3 | parse = "(?P\\d+)\\.(?P\\d+)\\.(?P\\d+)" 4 | serialize = ["{major}.{minor}.{patch}"] 5 | search = "{current_version}" 6 | replace = "{new_version}" 7 | regex = false 8 | ignore_missing_version = false 9 | ignore_missing_files = false 10 | tag = false 11 | sign_tags = false 12 | tag_name = "v{new_version}" 13 | tag_message = "Bump version: {current_version} → {new_version}" 14 | allow_dirty = false 15 | commit = false 16 | message = "Bump version: {current_version} → {new_version}" 17 | commit_args = "" 18 | setup_hooks = [] 19 | pre_commit_hooks = [] 20 | post_commit_hooks = [] 21 | 22 | [[tool.bumpversion.files]] 23 | filename = 'mbuild/__init__.py' 24 | search = "__date__ = '\\d{{4}}-\\d{{2}}-\\d{{2}}'" 25 | replace = "__date__ = '{now:%Y-%m-%d}'" 26 | regex = true 27 | 28 | [[tool.bumpversion.files]] 29 | filename = 'mbuild/__init__.py' 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/BUG_REPORT.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Report a bug in mBuild 4 | 5 | --- 6 | 7 | **Bug summary** 8 | 9 | What were you trying to do and what happened instead? Please copy and paste the stack output 10 | 11 | 12 | **Code to reproduce the behavior** 13 | 14 | Please include a code snippet that can be used to reproduce this bug. 15 | 16 | ```python 17 | # Paste your code here 18 | # 19 | # 20 | ``` 21 | 22 | **Software versions** 23 | 24 | - Which version of mBuild are you using? (`python -c "import mbuild as mb; print(mb.__version__)"`) 25 | - Which version of Python (`python --version`)? 26 | - Which operating system? 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an improvement to mBuild 4 | 5 | --- 6 | 7 | **Describe the behavior you would like added to mBuild** 8 | A clear and concise description of what the proposed idea is. 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. 12 | 13 | **Describe alternatives you've considered** 14 | A clear and concise description of any alternative solutions or features you've considered. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/QUESTION.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Questions/discussions 3 | about: For usage questions, important notes, and other discussions. 4 | 5 | --- 6 | 7 | **A summary of the question or discussion topic.** 8 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### PR Summary: 2 | 3 | ### PR Checklist 4 | ------------ 5 | - [ ] Includes appropriate unit test(s) 6 | - [ ] Appropriate docstring(s) are added/updated 7 | - [ ] Code is (approximately) PEP8 compliant 8 | - [ ] Issue(s) raised/addressed? 9 | -------------------------------------------------------------------------------- /.github/workflows/CI.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - "main" 7 | pull_request: 8 | branches: 9 | - "main" 10 | schedule: 11 | - cron: "0 0 * * *" 12 | 13 | jobs: 14 | test: 15 | if: github.event.pull_request.draft == false 16 | name: mBuild Tests (python) 17 | runs-on: ${{ matrix.os }} 18 | strategy: 19 | fail-fast: false 20 | matrix: 21 | os: [ubuntu-latest] 22 | python-version: ["3.9", "3.10", "3.11", "3.12"] 23 | 24 | defaults: 25 | run: 26 | shell: bash -l {0} 27 | 28 | steps: 29 | - uses: actions/checkout@v4 30 | name: Checkout Branch / Pull Request 31 | 32 | - name: Install Mamba (Linux) 33 | uses: mamba-org/setup-micromamba@v2 34 | with: 35 | environment-file: environment-dev.yml 36 | create-args: >- 37 | python=${{ matrix.python-version }} 38 | 39 | - name: Install Package 40 | run: python -m pip install -e . 41 | 42 | - name: Test (OS -> ${{ matrix.os }} / Python -> ${{ matrix.python-version }}) 43 | run: python -m pytest -v --cov=mbuild --cov-report=xml --cov-append --cov-config=setup.cfg --color yes --pyargs mbuild 44 | 45 | - name: Upload Coverage Report 46 | uses: codecov/codecov-action@v5 47 | with: 48 | name: mBuild-Coverage 49 | verbose: true 50 | files: ./coverage.xml 51 | 52 | arch-test: 53 | if: github.event.pull_request.draft == false 54 | name: mBuild Tests (arch) 55 | runs-on: ${{ matrix.os }} 56 | strategy: 57 | fail-fast: false 58 | matrix: 59 | os: [macOS-latest, macOS-13, ubuntu-latest] 60 | python-version: ["3.12"] 61 | 62 | defaults: 63 | run: 64 | shell: bash -l {0} 65 | 66 | steps: 67 | - uses: actions/checkout@v4 68 | name: Checkout Branch / Pull Request 69 | 70 | - name: Install Mamba (Linux) 71 | uses: mamba-org/setup-micromamba@v2 72 | with: 73 | environment-file: environment-dev.yml 74 | create-args: >- 75 | python=${{ matrix.python-version }} 76 | 77 | - name: Install Package 78 | run: python -m pip install -e . 79 | 80 | - name: Test (OS -> ${{ matrix.os }} / Python -> ${{ matrix.python-version }}) 81 | run: python -m pytest -v --cov=mbuild --cov-report=xml --cov-append --cov-config=setup.cfg --color yes --pyargs mbuild 82 | 83 | wsl-test: 84 | if: github.event.pull_request.draft == false 85 | name: mBuild Tests (WSL) 86 | runs-on: windows-latest 87 | 88 | steps: 89 | - uses: actions/checkout@v4 90 | name: Checkout Branch / Pull Request 91 | 92 | - uses: Vampire/setup-wsl@v4 93 | with: 94 | distribution: Ubuntu-24.04 95 | wsl-shell-user: runner 96 | name: Set up WSL 97 | 98 | - name: Install mBuild and run pytest 99 | shell: wsl-bash {0} 100 | run: | 101 | wget https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Linux-x86_64.sh -O $HOME/Miniforge3.sh 102 | bash $HOME/Miniforge3.sh -b -p $HOME/miniforge 103 | echo 'export PATH=$HOME/miniforge/bin:$PATH' >> ~/.bashrc 104 | export PATH=$HOME/miniforge/bin:$PATH 105 | source ~/.bashrc 106 | source $HOME/miniforge/etc/profile.d/conda.sh 107 | mamba update -n base --all -y 108 | mamba env create -f environment-dev.yml python=3.12 -y 109 | conda activate mbuild-dev 110 | pip install -e . --prefix=$HOME/tmp_egginfo --no-build-isolation 111 | python -m pytest -v --color yes --pyargs mbuild 112 | 113 | docker: 114 | runs-on: ubuntu-latest 115 | needs: test 116 | name: Build Docker Image 117 | if: github.event_name != 'pull_request' 118 | 119 | steps: 120 | - name: Set up Docker Buildx 121 | uses: docker/setup-buildx-action@v3 122 | 123 | - name: Login to DockerHub 124 | uses: docker/login-action@v3 125 | with: 126 | username: ${{ secrets.DOCKERHUB_USERNAME }} 127 | password: ${{ secrets.DOCKERHUB_PASSWORD }} 128 | 129 | - name: Get Tagged Version 130 | run: | 131 | echo "DOCKER_TAGS=mosdef/mbuild:${GITHUB_REF_NAME}, mosdef/mbuild:stable" >> $GITHUB_ENV 132 | if: github.ref_type == 'tag' 133 | 134 | - name: Get Push Version 135 | run: | 136 | echo "DOCKER_TAGS=mosdef/mbuild:${GITHUB_REF_NAME}, mosdef/mbuild:latest" >> $GITHUB_ENV 137 | if: github.ref_type == 'branch' 138 | 139 | - name: Docker Image Info 140 | run: | 141 | echo Docker Image tags: ${DOCKER_TAGS} 142 | 143 | - name: Build and Push 144 | uses: docker/build-push-action@v6 145 | with: 146 | push: true 147 | tags: ${{ env.DOCKER_TAGS }} 148 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | schedule: 9 | - cron: "50 6 * * 0" 10 | 11 | jobs: 12 | analyze: 13 | name: Analyze 14 | runs-on: ubuntu-latest 15 | permissions: 16 | actions: read 17 | contents: read 18 | security-events: write 19 | 20 | strategy: 21 | fail-fast: false 22 | matrix: 23 | language: [ python ] 24 | 25 | steps: 26 | - name: Checkout 27 | uses: actions/checkout@v3 28 | 29 | - name: Initialize CodeQL 30 | uses: github/codeql-action/init@v2 31 | with: 32 | languages: ${{ matrix.language }} 33 | queries: +security-and-quality 34 | 35 | - name: Autobuild 36 | uses: github/codeql-action/autobuild@v2 37 | 38 | - name: Perform CodeQL Analysis 39 | uses: github/codeql-action/analyze@v2 40 | with: 41 | category: "/language:${{ matrix.language }}" 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | test-output.xml 2 | *.py[cod] 3 | *.pymon 4 | *.ipynb_checkpoints 5 | *DS_Store* 6 | 7 | # C extensions 8 | *.so 9 | 10 | # Tmp Files 11 | *.swp 12 | 13 | # Packages 14 | *.egg 15 | *.egg-info 16 | dist 17 | build 18 | eggs 19 | parts 20 | bin 21 | var 22 | sdist 23 | develop-eggs 24 | .installed.cfg 25 | .pypirc 26 | 27 | # Installer logs 28 | pip-log.txt 29 | 30 | # Unit test / coverage reports 31 | .coverage 32 | .tox 33 | nosetests.xml 34 | htmlcov 35 | .cache 36 | .pytest_cache/ 37 | 38 | # Translations 39 | *.mo 40 | 41 | # Complexity 42 | output/*.html 43 | output/*/index.html 44 | 45 | # Sphinx 46 | docs/_build 47 | 48 | # PyCharm 49 | .idea 50 | .idea/* 51 | 52 | # VSCode 53 | .vscode 54 | .vscode/* 55 | 56 | # Vagrant 57 | .vagrant 58 | Vagrantfile 59 | 60 | # rope project settings 61 | .ropeproject 62 | 63 | #conda version 64 | __conda_version__.txt 65 | mbuild/version.py 66 | 67 | #virtual env 68 | .env/ 69 | 70 | # protobuf generated py file 71 | compound_pb2.py 72 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | ci: 2 | autofix_commit_msg: | 3 | [pre-commit.ci] auto fixes from pre-commit.com hooks 4 | for more information, see https://pre-commit.ci 5 | autofix_prs: true 6 | autoupdate_commit_msg: '[pre-commit.ci] pre-commit autoupdate' 7 | autoupdate_schedule: weekly 8 | skip: [] 9 | submodules: false 10 | repos: 11 | - repo: https://github.com/astral-sh/ruff-pre-commit 12 | # Ruff version. 13 | rev: v0.11.12 14 | hooks: 15 | # Run the linter. 16 | - id: ruff 17 | args: [--line-length=80, --fix] 18 | # Run the formatter. 19 | - id: ruff-format 20 | - repo: https://github.com/pre-commit/pre-commit-hooks 21 | rev: v5.0.0 22 | hooks: 23 | - id: check-yaml 24 | - id: end-of-file-fixer 25 | - id: trailing-whitespace 26 | 27 | - repo: https://github.com/pycqa/isort 28 | rev: 6.0.1 29 | hooks: 30 | - id: isort 31 | name: isort (python) 32 | args: [--profile=black, --line-length=80] 33 | -------------------------------------------------------------------------------- /.readthedocs.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | formats: 3 | - htmlzip 4 | - pdf 5 | conda: 6 | environment: docs/docs-env.yml 7 | build: 8 | os: ubuntu-20.04 9 | tools: 10 | python: "mambaforge-4.10" 11 | sphinx: 12 | builder: html 13 | configuration: docs/conf.py 14 | fail_on_warning: false 15 | -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | # This CITATION.cff file was generated with cffinit. 2 | # Visit https://bit.ly/cffinit to generate yours today! 3 | 4 | cff-version: 1.2.0 5 | title: >- 6 | "mBuild: A hierarchical, component based molecule builder." 7 | message: "Please cite this software using these metadata and the preferred citation." 8 | type: software 9 | authors: 10 | - given-names: Christoph 11 | family-names: Klein 12 | affiliation: "Vanderbilt University" 13 | - given-names: "Andrew Z." 14 | family-names: Summers 15 | affiliation: "Vanderbilt University" 16 | orcid: 'https://orcid.org/0000-0001-8477-3059' 17 | - given-names: "Matthew W." 18 | family-names: Thompson 19 | affiliation: "Vanderbilt University" 20 | orcid: 'https://orcid.org/0000-0002-1460-3983' 21 | - given-names: "Justin B." 22 | family-names: Gilmer 23 | affiliation: "Vanderbilt University" 24 | orcid: 'https://orcid.org/0000-0002-6915-5591' 25 | - given-names: "Co D." 26 | family-names: Quach 27 | affiliation: "Vanderbilt University" 28 | orcid: 'https://orcid.org/0000-0002-1255-4161' 29 | - given-names: Umesh 30 | family-names: Timalsina 31 | affiliation: "Vanderbilt University" 32 | orcid: 'https://orcid.org/0000-0002-5430-3993' 33 | - given-names: Peter 34 | family-names: Volgyesi 35 | orcid: 'https://orcid.org/0000-0002-7478-4317' 36 | affiliation: "Vanderbilt University" 37 | - given-names: Janos 38 | family-names: Sallai 39 | affiliation: "Vanderbilt University" 40 | - given-names: "Chris R." 41 | family-names: Iacovella 42 | affiliation: "Vanderbilt University" 43 | orcid: 'https://orcid.org/0000-0003-0557-0427' 44 | - given-names: "Clare M." 45 | family-names: McCabe 46 | affiliation: "Vanderbilt University" 47 | orcid: 'https://orcid.org/0000-0002-8552-9135' 48 | - given-names: "Peter T." 49 | family-names: Cummings 50 | affiliation: "Vanderbilt University" 51 | orcid: 'https://orcid.org/0000-0002-9766-2216' 52 | repository-code: 'https://github.com/mosdef-hub/mbuild' 53 | url: 'https://mbuild.mosdef.org' 54 | repository: 'https://github.com/mosdef-hub/mbuild' 55 | repository-artifact: 'https://github.com/mosdef-hub/mbuild/releases' 56 | abstract: >- 57 | With just a few lines of mBuild code, you can 58 | assemble reusable components into complex molecular 59 | systems for molecular simulations. 60 | 61 | mBuild is designed to minimize or even eliminate the need to explicitly translate and orient components when building systems: you simply tell it to connect two pieces! 62 | 63 | mBuild keeps track of the system’s topology so you don’t have to worry about manually defining bonds when constructing chemically bonded structures from smaller components. 64 | keywords: 65 | - Python 66 | - Reproducibility 67 | - "Molecular Simulation" 68 | - "computational chemistry" 69 | - chemistry 70 | - 'TRUE' 71 | - mosdef 72 | license: "MIT" 73 | preferred-citation: 74 | type: "article" 75 | authors: 76 | - given-names: Christoph 77 | family-names: Klein 78 | affiliation: "Vanderbilt University" 79 | - given-names: Janos 80 | family-names: Sallai 81 | affiliation: "Vanderbilt University" 82 | - given-names: "Trevor J." 83 | family-names: Jones 84 | affiliation: "Vanderbilt University" 85 | - given-names: "Chris R." 86 | family-names: Iacovella 87 | affiliation: "Vanderbilt University" 88 | orcid: 'https://orcid.org/0000-0003-0557-0427' 89 | - given-names: "Clare" 90 | family-names: McCabe 91 | affiliation: "Vanderbilt University" 92 | orcid: 'https://orcid.org/0000-0002-8552-9135' 93 | - given-names: "Peter T." 94 | family-names: Cummings 95 | affiliation: "Vanderbilt University" 96 | orcid: 'https://orcid.org/0000-0002-9766-2216' 97 | title: "A Hierarchical, Component Based Approach to Screening Properties of Soft Matter" 98 | year: "2016" 99 | doi: "10.1007/978-981-10-1128-3_5" 100 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributions are welcomed via [pull requests on GitHub](https://github.com/mosdef-hub/mbuild/pulls). Developers and/or 2 | users will review requested changes and make comments. The rest of this file will serve as a set of general guidelines 3 | for contributors. 4 | 5 | # Features 6 | 7 | ## Implement functionality in a general and flexible fashion 8 | 9 | mBuild is designed to be general and flexible, not limited to single chemistries, file formats, simulation engines, or 10 | simulation methods. Additions to core features should attempt to provide something that is applicable to a variety of 11 | use-cases and not targeted at only the focus area of your research. However, some specific features targeted toward 12 | a limited use case may be appropriate. Speak to the developers before writing your code and they will help you make design 13 | choices that allow flexibility. 14 | 15 | # Version control 16 | 17 | We currently use the "standard" Pull Request model. Contributions should be implemented on feature branches of forks. 18 | Please try to keep the `master` branch of your fork up-to-date with the `master` branch of the main repository. 19 | 20 | ## Propose a single set of related changes 21 | 22 | Small changes are preferred over large changes. A major contribution can often be broken down into smaller PRs. Large PRs that 23 | affect many parts of the codebase can be harder to review and are more likely to cause merge conflicts. 24 | 25 | # Source code 26 | 27 | ## Use a consistent style 28 | 29 | It is important to have a consistent style throughout the source code. The following criteria are desired: 30 | 31 | * Lines wrapped to 80 characters 32 | * Lines are indented with spaces 33 | * Lines do not end with whitespace 34 | * For other details, refer to [PEP8](https://www.python.org/dev/peps/pep-0008) 35 | 36 | We use [pre-commit](https://pre-commit.com/) to automatically check our code style. Pre-commit is included in the dev environment and its git hooks can be installed using: 37 | 38 | ```bash 39 | pre-commit install 40 | ``` 41 | 42 | ## Document code with comments 43 | 44 | All public-facing functions should have docstrings using the numpy style. This includes concise paragraph-style description 45 | of what the class or function does, relevant limitations and known issues, and descriptions of arguments. Internal functions 46 | can have simple one-liner docstrings. 47 | 48 | 49 | # Tests 50 | 51 | ## Write unit tests 52 | 53 | All new functionality in mBuild should be tested with automatic unit tests that execute in a few seconds. These tests 54 | should attempt to cover all options that the user can select. All or most of the added lines of source code should be 55 | covered by unit test(s). We currently use [pytest](https://docs.pytest.org/en/latest/), which can be executed simply by calling 56 | `pytest` from the root directory of the package. 57 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM continuumio/miniconda3:23.5.2-0-alpine AS builder 2 | 3 | EXPOSE 8888 4 | 5 | LABEL maintainer.name="mosdef-hub"\ 6 | maintainer.url="https://mosdef.org" 7 | 8 | ENV PATH /opt/conda/bin:$PATH 9 | 10 | USER root 11 | 12 | ADD . /mbuild 13 | 14 | WORKDIR /mbuild 15 | 16 | # Create a group and user 17 | RUN addgroup -S anaconda && adduser -S anaconda -G anaconda 18 | 19 | RUN apk update && apk add libarchive &&\ 20 | conda update conda -yq && \ 21 | conda config --set always_yes yes --set changeps1 no && \ 22 | . /opt/conda/etc/profile.d/conda.sh && \ 23 | conda install -c conda-forge mamba git && \ 24 | mamba env create --file environment-dev.yml python=3.12 && \ 25 | conda activate mbuild-dev && \ 26 | mamba install -c conda-forge jupyter && \ 27 | pip install -e .&& \ 28 | echo "source activate mbuild-dev" >> \ 29 | /home/anaconda/.profile && \ 30 | conda clean -afy && \ 31 | mkdir -p /home/anaconda/data && \ 32 | chown -R anaconda:anaconda /mbuild && \ 33 | chown -R anaconda:anaconda /opt && \ 34 | chown -R anaconda:anaconda /home/anaconda 35 | 36 | WORKDIR /home/anaconda 37 | 38 | COPY devtools/docker-entrypoint.sh /entrypoint.sh 39 | 40 | RUN chmod a+x /entrypoint.sh 41 | 42 | USER anaconda 43 | 44 | ENTRYPOINT ["/entrypoint.sh"] 45 | CMD ["jupyter"] 46 | -------------------------------------------------------------------------------- /LICENSE.rst: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Vanderbilt University 4 | 5 | With the exceptions noted below, this code is released under the MIT License: 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | this software and associated documentation files (the "Software"), to deal in 9 | the Software without restriction, including without limitation the rights to 10 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | the Software, and to permit persons to whom the Software is furnished to do so, 12 | subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | ---------------------------------------------------------------------- 25 | 26 | The method mbuild/box.py:Box._normalize_box was heavily inspired and 27 | in certain cases, copied from the 28 | garnett/trajectory.py:Trajectory._regularize_box method in the 29 | garnett python package. Garnett is BSD 3-Clause licensed with the following 30 | notice: 31 | 32 | BSD 3-Clause License for garnett 33 | 34 | Copyright (c) 2020 The Regents of the University of Michigan 35 | All rights reserved. 36 | 37 | Redistribution and use in source and binary forms, with or without 38 | modification, are permitted provided that the following conditions are met: 39 | 40 | 1. Redistributions of source code must retain the above copyright notice, 41 | this list of conditions and the following disclaimer. 42 | 43 | 2. Redistributions in binary form must reproduce the above copyright notice, 44 | this list of conditions and the following disclaimer in the documentation 45 | and/or other materials provided with the distribution. 46 | 47 | 3. Neither the name of the copyright holder nor the names of its contributors 48 | may be used to endorse or promote products derived from this software without 49 | specific prior written permission. 50 | 51 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 52 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 53 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 54 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 55 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 56 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 57 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 58 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 59 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 60 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 61 | 62 | ---------------------------------------------------------------------- 63 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE.rst 2 | global-include *.pdb *.mol2 *.smi *.xml *.xyz *.gsd *.cif *.sdf 3 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | ignore: 2 | - "mbuild/examples" 3 | - "mbuild/tests" 4 | -------------------------------------------------------------------------------- /devtools/README.md: -------------------------------------------------------------------------------- 1 | Developer Notes / Tools / License 2 | ================================= 3 | 4 | Assorted notes for developers. 5 | 6 | Most of these tools were adapted from MDTraj and are released under the following 7 | license: 8 | 9 | License 10 | ------- 11 | Copyright (c) 2012-2015 Stanford University and the Authors 12 | All rights reserved. 13 | 14 | Redistribution and use of all files in this folder (devtools) and 15 | (../basesetup.py, ../setup.py) files in source and binary forms, with or without 16 | modification, are permitted provided that the following conditions are met: 17 | 18 | 1. Redistributions of source code must retain the above copyright notice, this 19 | list of conditions and the following disclaimer. 20 | 21 | 2. Redistributions in binary form must reproduce the above copyright notice, 22 | this list of conditions and the following disclaimer in the documentation 23 | and/or other materials provided with the distribution. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 26 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 27 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 29 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 31 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | -------------------------------------------------------------------------------- /devtools/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | . /opt/conda/etc/profile.d/conda.sh 4 | conda activate base 5 | conda activate mbuild-dev 6 | 7 | if [ "$@" == "jupyter" ]; then 8 | jupyter notebook --no-browser --notebook-dir /home/anaconda/data --ip="0.0.0.0" 9 | else 10 | $@ 11 | fi 12 | -------------------------------------------------------------------------------- /docs/_templates/footer.html: -------------------------------------------------------------------------------- 1 | {%extends "!footer.html" %} 2 | {% block extrafooter %} 3 | 23 | {{ super() }} 24 | {% endblock %} 25 | -------------------------------------------------------------------------------- /docs/docs-env.yml: -------------------------------------------------------------------------------- 1 | name: mbuild-docs 2 | channels: 3 | - jaimergp/label/unsupported-cudatoolkit-shim 4 | - conda-forge 5 | dependencies: 6 | - ele 7 | - numpy 8 | - importlib_resources 9 | - python=3.11 10 | - ipython 11 | - boltons 12 | - networkx 13 | - gmso 14 | - lark 15 | - mock 16 | - cairosvg 17 | - requests 18 | - lxml 19 | - numpydoc 20 | - sphinx<8.0 21 | - sphinx_rtd_theme 22 | - sphinxcontrib-svg2pdfconverter[CairoSVG] 23 | - widgetsnbextension 24 | - nbsphinx 25 | - pip 26 | -------------------------------------------------------------------------------- /docs/files/mbuild_citation.bib: -------------------------------------------------------------------------------- 1 | @Inbook{Klein2016, 2 | author = "Klein, Christoph and Sallai, J{\'a}nos and Jones, Trevor J. and Iacovella, Christopher R. and McCabe, Clare and Cummings, Peter T.", 3 | editor = "Snurr, Randall Q and Adjiman, Claire S. and Kofke, David A.", 4 | title = "A Hierarchical, Component Based Approach to Screening Properties of Soft Matter", 5 | bookTitle = "Foundations of Molecular Modeling and Simulation: Select Papers from FOMMS 2015", 6 | year = "2016", 7 | publisher = "Springer Singapore", 8 | address = "Singapore", 9 | pages = "79--92", 10 | abstract = "In prior work, Sallai, et al. introduced the concept and algorithms of building molecular topologies through the use of a hierarchical data structure and the use of an affine coordinate transformation to connect molecular components. In this work, we expand upon the original concept and present a refined version of this software, termed mBuild , which is a general tool for constructing arbitrarily complex input configurations for molecular simulation in a programmatic fashion. Basic molecular components are connected using an equivalence operator which reduces and often removes the need for users to explicitly rotate and translate components as they assemble systems. Additionally, the programmatic nature of this approach and integration with the scientific Python ecosystem seamlessly exposes high-level variables that users can tune to alter the chemical composition of their systems, such as mixtures of polymers of different chain lengths and surface patterning. Leveraging these features, we demonstrate how mBuild serves as a stepping stone towards screening and performing optimizations in chemical parameter space of complex materials by performing automated screening studies of monolayer systems as a function of graft type, degree of polymerization, and surface density.", 11 | isbn = "978-981-10-1128-3", 12 | doi = "10.1007/978-981-10-1128-3_5", 13 | url = "https://doi.org/10.1007/978-981-10-1128-3_5" 14 | } 15 | -------------------------------------------------------------------------------- /docs/files/mbuild_citation.ris: -------------------------------------------------------------------------------- 1 | TY - CHAP 2 | AU - Klein, Christoph 3 | AU - Sallai, János 4 | AU - Jones, Trevor J. 5 | AU - Iacovella, Christopher R. 6 | AU - McCabe, Clare 7 | AU - Cummings, Peter T. 8 | ED - Snurr, Randall Q 9 | ED - Adjiman, Claire S. 10 | ED - Kofke, David A. 11 | PY - 2016 12 | DA - 2016// 13 | TI - A Hierarchical, Component Based Approach to Screening Properties of Soft Matter 14 | BT - Foundations of Molecular Modeling and Simulation: Select Papers from FOMMS 2015 15 | SP - 79 16 | EP - 92 17 | PB - Springer Singapore 18 | CY - Singapore 19 | AB - In prior work, Sallai, et al. introduced the concept and algorithms of building molecular topologies through the use of a hierarchical data structure and the use of an affine coordinate transformation to connect molecular components. In this work, we expand upon the original concept and present a refined version of this software, termed mBuild , which is a general tool for constructing arbitrarily complex input configurations for molecular simulation in a programmatic fashion. Basic molecular components are connected using an equivalence operator which reduces and often removes the need for users to explicitly rotate and translate components as they assemble systems. Additionally, the programmatic nature of this approach and integration with the scientific Python ecosystem seamlessly exposes high-level variables that users can tune to alter the chemical composition of their systems, such as mixtures of polymers of different chain lengths and surface patterning. Leveraging these features, we demonstrate how mBuild serves as a stepping stone towards screening and performing optimizations in chemical parameter space of complex materials by performing automated screening studies of monolayer systems as a function of graft type, degree of polymerization, and surface density. 20 | SN - 978-981-10-1128-3 21 | UR - https://doi.org/10.1007/978-981-10-1128-3_5 22 | DO - 10.1007/978-981-10-1128-3_5 23 | ID - Klein2016 24 | ER - 25 | -------------------------------------------------------------------------------- /docs/getting_started/example_system.rst: -------------------------------------------------------------------------------- 1 | Example System 2 | =============== 3 | 4 | 5 | Components in dashed boxes are drawn by hand using, e.g., `Avogadro `_ or generated elsewhere. 6 | `mBuild `_ builds up complex systems from simple building blocks through simple attachment sites, called a ``Port`` (i.e., connection points). Each building block is a python class that can be customized or created through the pre-built options in the ``mBuild`` library ( ``mbuild.lib`` ). A hierarchical structure of parents and children is created through these classes, which can be easily parsed or modified. 7 | This allows `mBuild `_ to generate chemical structures in a piecemeal fashion by creating or importing molecular sections, adding ports, and connecting the ports to form bonds. 8 | Together with `Signac `_, this functionality enables an automatic and dynamic method for generating chemical systems, allowing large-scale chemical and materials screening with minimal user interaction. 9 | 10 | Ultimately, complex systems can be created with just a line or two 11 | of code. Additionally, this approach seamlessly exposes tunable parameters within 12 | the hierarchy so you can actually create whole families of structures 13 | by adjusting a variable or two:: 14 | 15 | pattern = Random2DPattern(20) # A random arrangement of 20 pieces on a 2D surface. 16 | brush_layer = BrushLayer(chain_lenth=20, pattern=pattern, tile_x=3, tile_y=2) 17 | 18 | .. figure:: ../images/pmpc.png 19 | :width: 100 % 20 | :align: center 21 | 22 | **Zwitterionic brushes on beta-cristobalite substrate.** Example system that can be created using mBuild. 23 | Components in dashed boxes are created from some external tool like Avogadro or SMILES strings. 24 | Components in solid boxes are created from these smaller dashed components and then constructed into larger, 25 | more complex systems using mBuild functionality. 26 | 27 | .. image:: https://img.shields.io/badge/license-MIT-blue.svg 28 | :target: http://opensource.org/licenses/MIT 29 | 30 | Various sub-portions of this library may be independently distributed under 31 | different licenses. See those files for their specific terms. 32 | -------------------------------------------------------------------------------- /docs/getting_started/installation/installation.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Installation 3 | ============ 4 | 5 | Install with `conda `_ 6 | ----------------------------------------------------------------- 7 | :: 8 | 9 | $ conda install -c conda-forge mbuild 10 | 11 | Alternatively you can add all the required channels to your ``.condarc`` 12 | after which you can simply install without specifying the channels:: 13 | 14 | $ conda config --add channels conda-forge 15 | $ conda install mbuild 16 | 17 | .. note:: 18 | The order in which channels are added matters: ``conda-forge`` should be the highest priority as a result of being added last. In your ``.condarc`` file, it should be listed first. 19 | 20 | .. note:: 21 | Because ``packmol`` binaries are unavailable for windows from ``conda-forge`` channel, to use mbuild with conda in a Windows system requires the ``omnia`` channel. Use the following command to use ``mbuild`` with conda in a Windows system:: 22 | 23 | $ conda install -c conda-forge -c omnia mbuild 24 | 25 | .. note:: 26 | The `MDTraj website `_ makes a 27 | nice case for using Python and in particular the 28 | `Anaconda scientific python distribution `_ 29 | to manage your numerical and scientific Python packages. 30 | 31 | Install an editable version from source 32 | --------------------------------------- 33 | 34 | To make your life easier, we recommend that you use a pre-packaged Python 35 | distribution like `Miniconda `_ 36 | in order to get all of the dependencies:: 37 | 38 | $ git clone https://github.com/mosdef-hub/mbuild 39 | $ cd mbuild 40 | $ conda env create -f environment-dev.yml 41 | $ conda activate mbuild-dev 42 | $ pip install -e . 43 | 44 | .. note:: 45 | The above installation is for OSX and Unix. If you are using Windows, use environment-win.yml instead of environment-dev.yml 46 | 47 | 48 | Install pre-commit 49 | ------------------ 50 | 51 | We use `pre-commit `_ to automatically handle our code formatting and this package is included in the dev environment. 52 | With the ``mbuild-dev`` conda environment active, pre-commit can be installed locally as a git hook by running:: 53 | 54 | $ pre-commit install 55 | 56 | And (optional) all files can be checked by running:: 57 | 58 | $ pre-commit run --all-files 59 | 60 | 61 | Supported Python Versions 62 | ------------------------- 63 | 64 | Python 3.9, 3.10 and 3.11 are officially supported, including testing during 65 | development and packaging. Support for Python 2.7 has been dropped as of 66 | August 6, 2019. Other Python versions, such as 3.12 and 3.8 and older, may 67 | successfully build and function but no guarantee is made. 68 | 69 | Testing your installation 70 | ------------------------- 71 | 72 | mBuild uses `py.test `_ for unit testing. To run them simply run the following while in the base directory:: 73 | 74 | $ conda install pytest 75 | $ py.test -v 76 | 77 | Building the documentation 78 | -------------------------- 79 | 80 | mBuild uses `sphinx `_ to build its documentation. To build the docs locally, run the following while in the ``docs`` directory:: 81 | 82 | $ cd docs 83 | $ conda env create -f docs-env.yml 84 | $ conda activate mbuild-docs 85 | $ make html 86 | -------------------------------------------------------------------------------- /docs/getting_started/installation/installation_toc.rst: -------------------------------------------------------------------------------- 1 | ============== 2 | Installation 3 | ============== 4 | 5 | 6 | .. toctree:: 7 | installation 8 | docker 9 | -------------------------------------------------------------------------------- /docs/getting_started/quick_start/Box_example.rst: -------------------------------------------------------------------------------- 1 | Box 2 | ======================== 3 | 4 | 5 | Import the required mbuild package. 6 | 7 | .. code:: ipython3 8 | 9 | import mbuild as mb 10 | 11 | 12 | Orthogonal Box 13 | ------------------------ 14 | 15 | Build an empty orthogonal **mBuild** Box (i.e., the angle in degrees are 𝛼 = 90, 𝛽 = 90, 𝛾 = 90) measuring 4.0 nm in all the x, y, and z-dimensions. 16 | 17 | .. note:: 18 | Note: if the angles are not specified, the system will default to an orthogonal box 19 | (i.e., the angle in degrees are 𝛼 = 90, 𝛽 = 90, 𝛾 = 90). 20 | 21 | .. code:: ipython3 22 | 23 | empty_box = mb.Box(lengths=[4.0, 4.0, 4.0], angles=[90, 90, 90]) 24 | 25 | 26 | Non-Orthogonal Box 27 | ------------------------ 28 | 29 | Build an empty non-orthogonal **mBuild** Box (i.e., the angle in degrees are 𝛼 = 90, 𝛽 = 90, 𝛾 = 120) measuring 4.0 nm in the x and y-dimensions, and 5.0 nm in the z-dimension. 30 | 31 | .. code:: ipython3 32 | 33 | empty_box = mb.Box(lengths=[4.0, 4.0, 5.0], angles=[90, 90, 120]) 34 | -------------------------------------------------------------------------------- /docs/getting_started/quick_start/fill_box_example.rst: -------------------------------------------------------------------------------- 1 | Fill Box 2 | ======== 3 | 4 | 5 | All-Atom (AA) Hexane and Ethanol System 6 | --------------------------------------- 7 | 8 | .. note:: 9 | `foyer `_ is used in conjunction with ``mBuild`` in 10 | the following example to demonstrate how the `MoSDeF `_ 11 | libraries can be used together to generate a simulation box. 12 | 13 | Import the required mbuild package. 14 | 15 | .. code:: ipython3 16 | 17 | import mbuild as mb 18 | 19 | 20 | Construct an all-atom (AA) hexane and ethanol using the OPLS-AA force field (FF), 21 | which is shipped as a standard `foyer `_ FF. 22 | The hexane and ethanol molecules will be created using `smiles strings `_. 23 | The hexane and ethanol residues will be named `"HEX"` and `"ETO"`, respectively. 24 | Lastly, the hexane and ethanol molecule's configuration will be energy minimized, properly reorienting the molecule to the specified FF, which is sometimes needed for some simulation engines to ensure the initial configuration energy is not too high. 25 | 26 | .. note:: 27 | The energy minimize step requires the `foyer `_ package. 28 | 29 | .. code:: ipython3 30 | 31 | hexane = mb.load('CCCCCC', smiles=True) 32 | hexane.name = 'HEX' 33 | hexane.energy_minimize(forcefield='oplsaa', steps=10**4) 34 | 35 | 36 | ethanol = mb.load('CCO', smiles=True) 37 | ethanol.name = 'ETO' 38 | ethanol.energy_minimize(forcefield='oplsaa', steps=10**4) 39 | 40 | The liquid box is built to a density of 680 kg/m\ :sup:`3`, with a 50/50 mol ratio of hexane and ethanol, and will be in an orthogonal box measuring 5.0 nm in the x, y, and z-dimensions. 41 | 42 | .. code:: ipython3 43 | 44 | box_liq = mb.fill_box(compound= [hexane, ethanol], 45 | density=680, 46 | compound_ratio=[0.5, 0.5], 47 | box=[5.0, 5.0, 5.0]) 48 | 49 | 50 | United Atom (UA) Methane System 51 | ------------------------------- 52 | 53 | .. note:: 54 | `foyer `_ is used in conjunction with ``mBuild`` in 55 | the following example to demonstrate how the `MoSDeF `_ libraries 56 | integrate to generate a simulation box. A subset of the `TraPPE-United Atom `_ 57 | force field (FF) comes standard with the `foyer `_ software package. 58 | 59 | Import the required mbuild package. 60 | 61 | .. code:: ipython3 62 | 63 | import mbuild as mb 64 | 65 | 66 | Construct a pseudo-monatomic molecule (united atom (UA) methane), for use with the 67 | `TraPPE `_ FF. The UA methane, bead type `"_CH4"`, will be built as a child (``mbuild.Compound.children``), so the parent (``mbuild.Compound``) will 68 | allow a user-selected residue name (``mbuild.Compound.name``). If the methane is built using ``methane = mb.Compound(name="_CH4")``, then the user must keep the residue name `"_CH4"` or `foyer `_ will not recognize the bead type when using the standard TraPPE force field XML file. 69 | 70 | .. code:: ipython3 71 | 72 | methane = mb.Compound(name="MET") 73 | methane_child_bead = mb.Compound(name="_CH4") 74 | methane.add(methane_child_bead, inherit_periodicity=False) 75 | 76 | .. note:: 77 | The ``inherit_periodicity`` flag is an optional boolean (default=True), which replaces 78 | the periodicity of self with the periodicity of the Compound being added. 79 | 80 | The orthogonal liquid box contains 1230 methane molecules and measures 4.5 nm in all the x, y, and z-dimensions. 81 | 82 | .. code:: ipython3 83 | 84 | box_liq = mb.fill_box(compound=methane, 85 | n_compounds=1230, 86 | box=[4.5, 4.5, 4.5] 87 | ) 88 | -------------------------------------------------------------------------------- /docs/getting_started/quick_start/load_files.rst: -------------------------------------------------------------------------------- 1 | .. _QuickStart_Load_files: 2 | 3 | Load files 4 | ======================== 5 | 6 | 7 | mol2 files 8 | ------------------------ 9 | 10 | Create an ``mbuild.Compound`` (i.e., the "pentane" variable) by loading a molecule from a `mol2 `_ file. 11 | 12 | Import the required mbuild packages. 13 | 14 | .. code:: ipython3 15 | 16 | import mbuild as mb 17 | 18 | 19 | Load the "pentane.mol2" file from its directory. 20 | 21 | .. code:: ipython3 22 | 23 | pentane = mb.load("path_to_mol2_file/pentane.mol2") 24 | 25 | 26 | CIF files 27 | ------------------------ 28 | 29 | Build an ``mbuild.Compound`` (i.e., the "ETV_triclinic" variable) by loading a `Crystallographic Information File (CIF) `_ file and selecting the number of cell units to populate in the x, y, and z-dimensions. 30 | 31 | 32 | Import the required mbuild packages. 33 | 34 | .. code:: ipython3 35 | 36 | import mbuild as mb 37 | from mbuild.lattice import load_cif 38 | 39 | 40 | 41 | The `CIF `_ file is loaded using the ``load_cif`` function. Next, three (3) cell units shall be built for all the x, y, and z-dimensions with the populate function. Finally, the `CIF `_'s residues are named 'ETV'. 42 | 43 | .. code:: ipython3 44 | 45 | lattice_cif_ETV_triclinic = load_cif("path_to_cif_file/ETV_triclinic.cif") 46 | ETV_triclinic = lattice_cif_ETV_triclinic.populate(x=3, y=3, z=3) 47 | ETV_triclinic.name = 'ETV' 48 | 49 | 50 | Other file types 51 | ------------------------ 52 | mBuild also supports :ref:`loading_data` or files via hoomd_snapshot, GSD, SMILES strings, and ParmEd structures. 53 | -------------------------------------------------------------------------------- /docs/getting_started/quick_start/polymer_example.rst: -------------------------------------------------------------------------------- 1 | Polymer 2 | ======================== 3 | 4 | Use two (2) different monomer units, A and B, to construct a polymer, capping it with a carboxylic acid and amine end group. 5 | 6 | 7 | Import the required mbuild packages. 8 | 9 | .. code:: ipython3 10 | 11 | import mbuild as mb 12 | from mbuild.lib.recipes.polymer import Polymer 13 | 14 | 15 | 16 | Create the monomer units `comp_1` and `comp_2` using `SMILES strings `_. 17 | Set the `chain` as a ``Polymer`` class, adding `comp_1` and `comp_2` as the monomers A and B to the polymer. 18 | 19 | .. note:: 20 | Setting the indices identifies which atoms will be removed and have ports created in their place. 21 | 22 | 23 | .. code:: ipython3 24 | 25 | comp_1 = mb.load('CC', smiles=True) # mBuild compound of the monomer unit 26 | comp_2 = mb.load('COC', smiles=True) # mBuild compound of the monomer unit 27 | chain = Polymer() 28 | chain.add_monomer(compound=comp_1, 29 | indices=[2, -2], 30 | separation=.15, 31 | replace=True) 32 | 33 | chain.add_monomer(compound=comp_2, 34 | indices=[3, -1], 35 | separation=.15, 36 | replace=True) 37 | 38 | 39 | Select the carboxylic acid and amine end groups that we want to use for the head and tail of the polymer. 40 | Then, build the polymer with three (3) iterations of the AB sequence, and the selected head and tail end groups. 41 | 42 | 43 | .. code:: ipython3 44 | 45 | chain.add_end_groups(mb.load('C(=O)O',smiles=True), 46 | index=3, 47 | separation=0.15, 48 | duplicate=False, 49 | label="head") 50 | 51 | chain.add_end_groups(mb.load('N', smiles=True), 52 | index=-1, 53 | separation=0.13, 54 | duplicate=False, 55 | label="tail") 56 | 57 | chain.build(n=3, sequence='AB') 58 | chain.visualize() 59 | 60 | 61 | .. figure:: ../../images/polymer_example_image.png 62 | :width: 60 % 63 | :align: center 64 | 65 | This **example polymer** is 3 of the AB sequences together with carboxylic acid and amine end groups. 66 | -------------------------------------------------------------------------------- /docs/getting_started/quick_start/quick_start.rst: -------------------------------------------------------------------------------- 1 | ----------------------- 2 | Quick Start 3 | ----------------------- 4 | 5 | .. image:: https://img.shields.io/badge/license-MIT-blue.svg 6 | :target: http://opensource.org/licenses/MIT 7 | 8 | The `MoSDeF `_ software is comprised the following packages: 9 | * `mBuild `_ -- A hierarchical, component based molecule builder 10 | * `foyer `_ -- A package for atom-typing as well as applying and disseminating forcefields 11 | * `GMSO `_ -- Flexible storage of chemical topology for molecular simulation 12 | 13 | .. note:: 14 | **foyer** and **GMSO** are used together with **mBuild** to create all the required files to conduct the simulations. Run time parameters for a simulation engine need to be created by the user. 15 | 16 | In the following examples, different types of simulation boxes are constructed using the **MoSDeF** software. 17 | 18 | 19 | Molecular simulations are usually comprised of many molecules contained in a 20 | box (NPT and NVT ensembles), or boxes (GEMC and GCMC ensembles). 21 | The **mBuild** library allows for easy generation of the simulation 22 | box or boxes utilizing only a few lines of python code. 23 | 24 | 25 | The following tutorials are available either as html or interactive `jupyter `_ notebooks. 26 | 27 | 28 | .. toctree:: 29 | 30 | load_files 31 | Box_example 32 | fill_box_example 33 | polymer_example 34 | -------------------------------------------------------------------------------- /docs/getting_started/tutorials/ch3.pdb: -------------------------------------------------------------------------------- 1 | COMPND UNNAMED 2 | AUTHOR GENERATED BY OPEN BABEL 3 | ATOM 1 C LIG A 1 -1.750 1.662 0.000 1.00 0.00 C 4 | ATOM 2 H LIG A 1 -0.680 1.662 0.000 1.00 0.00 H 5 | ATOM 3 H LIG A 1 -2.107 2.431 0.653 1.00 0.00 H 6 | ATOM 4 H LIG A 1 -2.107 1.843 -0.993 1.00 0.00 H 7 | CONECT 1 2 3 4 8 | CONECT 2 1 9 | CONECT 3 1 10 | CONECT 4 1 11 | MASTER 0 0 0 0 0 0 0 0 4 0 4 0 12 | END 13 | -------------------------------------------------------------------------------- /docs/getting_started/tutorials/custom.css: -------------------------------------------------------------------------------- 1 | #notebook #notebook-container { 2 | width: 100% !important; 3 | padding: 0 !important; 4 | -webkit-box-shadow: 0 0 12px 1px rgba(87,87,87,0.2); 5 | box-shadow: 0 0 12px 1px rgba(87,87,87,0.2); 6 | font-family: "Lato","proxima-nova","Helvetica Neue",Arial,sans-serif; 7 | font-weight: normal; 8 | } 9 | 10 | dev.cell { 11 | padding: 0px; 12 | } 13 | 14 | body { 15 | font-family: "Roboto Slab","ff-tisa-web-pro","Georgia",Arial,sans-serif; 16 | font-weight: normal; 17 | color: #404040; 18 | min-height: 100%; 19 | overflow-x: hidden; 20 | background: #edf0f2; 21 | } 22 | 23 | #notebook { 24 | padding-bottom: 20px; 25 | } 26 | -------------------------------------------------------------------------------- /docs/getting_started/tutorials/ethane.mol2: -------------------------------------------------------------------------------- 1 | @MOLECULE 2 | RES 3 | 8 7 1 0 1 4 | SMALL 5 | NO_CHARGES 6 | @CRYSIN 7 | 7.1400 7.9380 6.6460 90.0000 90.0000 90.0000 1 1 8 | @ATOM 9 | 1 C 0.0000 -1.4000 -0.0000 C 1 RES 10 | 2 H -1.0700 -1.4000 -0.0000 H 1 RES 11 | 3 H 0.3570 -2.1690 0.6530 H 1 RES 12 | 4 H 0.3570 -1.5810 -0.9930 H 1 RES 13 | 5 C 0.0000 0.0000 0.0000 C 1 RES 14 | 6 H 1.0700 0.0000 0.0000 H 1 RES 15 | 7 H -0.3570 0.7690 0.6530 H 1 RES 16 | 8 H -0.3570 0.1810 -0.9930 H 1 RES 17 | @BOND 18 | 1 8 5 1 19 | 2 1 2 1 20 | 3 6 5 1 21 | 4 4 1 1 22 | 5 7 5 1 23 | 6 5 1 1 24 | 7 3 1 1 25 | @SUBSTRUCTURE 26 | 1 RES 1 RESIDUE 0 **** ROOT 0 27 | -------------------------------------------------------------------------------- /docs/getting_started/tutorials/generate_html.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | mkdir -p ~/.ipython/profile_default/static/custom/ 4 | cp custom.css ~/.ipython/profile_default/static/custom/custom.css 5 | ipython nbconvert *.ipynb 6 | -------------------------------------------------------------------------------- /docs/getting_started/tutorials/methane.mol2: -------------------------------------------------------------------------------- 1 | @MOLECULE 2 | RES 3 | 5 4 1 0 1 4 | SMALL 5 | NO_CHARGES 6 | @CRYSIN 7 | 7.0000 7.0000 6.4000 90.0000 90.0000 90.0000 1 1 8 | @ATOM 9 | 1 C 0.0000 0.0000 0.0000 C 1 RES 10 | 2 H 1.0000 0.0000 -0.7000 H 1 RES 11 | 3 H -1.0000 0.0000 -0.7000 H 1 RES 12 | 4 H 0.0000 1.0000 0.7000 H 1 RES 13 | 5 H 0.0000 -1.0000 0.7000 H 1 RES 14 | @BOND 15 | 1 1 2 1 16 | 2 1 3 1 17 | 3 1 4 1 18 | 4 1 5 1 19 | @SUBSTRUCTURE 20 | 1 RES 1 RESIDUE 0 **** ROOT 0 21 | -------------------------------------------------------------------------------- /docs/getting_started/tutorials/tutorial_methane.rst: -------------------------------------------------------------------------------- 1 | Methane: Compounds and bonds 2 | ---------------------------- 3 | 4 | **Note**: mBuild expects all distance units to be in nanometers. 5 | 6 | The primary building block in mBuild is a ``Compound``. Anything you 7 | construct will inherit from this class. Let’s start with some basic 8 | imports and initialization: 9 | 10 | .. code:: ipython3 11 | 12 | import mbuild as mb 13 | 14 | class Methane(mb.Compound): 15 | def __init__(self): 16 | super(Methane, self).__init__() 17 | 18 | Any ``Compound`` can contain other ``Compounds`` which can be added 19 | using its ``add()`` method. ``Compounds`` at the bottom of such a 20 | hierarchy are referred to as ``Particles``. Note however, that this is 21 | purely semantic in mBuild to help clearly designate the bottom of a 22 | hierarchy. 23 | 24 | .. code:: ipython3 25 | 26 | import mbuild as mb 27 | 28 | class Methane(mb.Compound): 29 | def __init__(self): 30 | super(Methane, self).__init__() 31 | carbon = mb.Particle(name='C') 32 | self.add(carbon, label='C[$]') 33 | 34 | hydrogen = mb.Particle(name='H', pos=[0.11, 0, 0]) 35 | self.add(hydrogen, label='HC[$]') 36 | 37 | By default a created ``Compound/Particle`` will be placed at ``0, 0, 0`` 38 | as indicated by its ``pos`` attribute. The ``Particle`` objects 39 | contained in a ``Compound``, the bottoms of the hierarchy, can be 40 | referenced via the ``particles`` method which returns a generator of all 41 | ``Particle`` objects contained below the ``Compound`` in the hierarchy. 42 | 43 | **Note:** All positions in mBuild are stored in nanometers. 44 | 45 | Any part added to a ``Compound`` can be given an optional, descriptive 46 | string label. If the label ends with the characters ``[$]``, a list will 47 | be created in the labels. Any subsequent parts added to the ``Compound`` 48 | with the same label prefix will be appended to the list. In the example 49 | above, we’ve labeled the hydrogen as ``HC[$]``. So this first part, with 50 | the label prefix ``HC``, is now referenceable via ``self['HC'][0]``. The 51 | next part added with the label ``HC[$]`` will be referenceable via 52 | ``self['HC'][1]``. 53 | 54 | Now let’s use these styles of referencing to connect the carbon to the 55 | hydrogen. Note that for typical use cases, you will almost never have to 56 | explicitly define a bond when using mBuild - this is just to show you 57 | what’s going on under the hood: 58 | 59 | .. code:: ipython3 60 | 61 | import mbuild as mb 62 | 63 | class Methane(mb.Compound): 64 | def __init__(self): 65 | super(Methane, self).__init__() 66 | carbon = mb.Particle(name='C') 67 | self.add(carbon, label='C[$]') 68 | 69 | hydrogen = mb.Particle(name='H', pos=[0.11, 0, 0]) 70 | self.add(hydrogen, label='HC[$]') 71 | 72 | self.add_bond((self[0], self['HC'][0])) 73 | 74 | As you can see, the carbon is placed in the zero index of ``self``. The 75 | hydrogen could be referenced via ``self[1]`` but since we gave it a 76 | fancy label, it’s also referenceable via ``self['HC'][0]``. 77 | 78 | Alright now that we’ve got the basics, let’s finish building our 79 | ``Methane`` and take a look at it: 80 | 81 | .. code:: ipython3 82 | 83 | import mbuild as mb 84 | 85 | class Methane(mb.Compound): 86 | def __init__(self): 87 | super(Methane, self).__init__() 88 | carbon = mb.Particle(name='C') 89 | self.add(carbon, label='C[$]') 90 | 91 | hydrogen = mb.Particle(name='H', pos=[0.1, 0, -0.07]) 92 | self.add(hydrogen, label='HC[$]') 93 | 94 | self.add_bond((self[0], self['HC'][0])) 95 | 96 | self.add(mb.Particle(name='H', pos=[-0.1, 0, -0.07]), label='HC[$]') 97 | self.add(mb.Particle(name='H', pos=[0, 0.1, 0.07]), label='HC[$]') 98 | self.add(mb.Particle(name='H', pos=[0, -0.1, 0.07]), label='HC[$]') 99 | 100 | self.add_bond((self[0], self['HC'][1])) 101 | self.add_bond((self[0], self['HC'][2])) 102 | self.add_bond((self[0], self['HC'][3])) 103 | 104 | .. code:: ipython3 105 | 106 | methane = Methane() 107 | methane.visualize() 108 | 109 | .. code:: ipython3 110 | 111 | # Save to .mol2 112 | methane.save('methane.mol2',overwrite=True) 113 | -------------------------------------------------------------------------------- /docs/getting_started/tutorials/tutorial_monolayer.rst: -------------------------------------------------------------------------------- 1 | Monolayer: Complex hierarchies, patterns, tiling and writing to files 2 | --------------------------------------------------------------------- 3 | 4 | **Note**: mBuild expects all distance units to be in nanometers. 5 | 6 | In this example, we’ll cover assembling more complex hierarchies of 7 | components using patterns, tiling and how to output systems to files. To 8 | illustrate these concepts, let’s build an alkane monolayer on a 9 | crystalline substrate. 10 | 11 | First, let’s build our monomers and functionalized them with a silane 12 | group which we can then attach to the substrate. The ``Alkane`` example 13 | uses the ``polymer`` tool to combine ``CH2`` and ``CH3`` repeat units. 14 | You also have the option to cap the front and back of the chain or to 15 | leave a ``CH2`` group with a dangling port. The ``Silane`` compound is a 16 | Si(OH)2 group with two ports facing out from the central Si. Lastly, we 17 | combine ``alkane`` with ``silane`` and add a label to ``AlkylSilane`` 18 | which points to, ``silane['down']``. This allows us to reference it 19 | later using ``AlkylSilane['down']`` rather than 20 | ``AlkylSilane['silane']['down']``. 21 | 22 | **Note:** In ``Compounds`` with multiple ``Ports``, by convention, we 23 | try to label every ``Port`` successively as ‘up’, ‘down’, ‘left’, 24 | ‘right’, ‘front’, ‘back’ which should roughly correspond to their 25 | relative orientations. This is a bit tricky to enforce because the 26 | system is so flexible so use your best judgement and try to be 27 | consistent! The more components we collect in our library with the same 28 | labeling conventions, the easier it becomes to build ever more complex 29 | structures. 30 | 31 | .. code:: ipython3 32 | 33 | import mbuild as mb 34 | 35 | from mbuild.lib.recipes import Alkane 36 | from mbuild.lib.moieties import Silane 37 | 38 | 39 | class AlkylSilane(mb.Compound): 40 | """A silane functionalized alkane chain with one Port. """ 41 | def __init__(self, chain_length): 42 | super(AlkylSilane, self).__init__() 43 | 44 | alkane = Alkane(chain_length, cap_end=False) 45 | self.add(alkane, 'alkane') 46 | silane = Silane() 47 | self.add(silane, 'silane') 48 | mb.force_overlap(self['alkane'], self['alkane']['down'], self['silane']['up']) 49 | 50 | # Hoist silane port to AlkylSilane level. 51 | self.add(silane['down'], 'down', containment=False) 52 | 53 | .. code:: ipython3 54 | 55 | AlkylSilane(5).visualize() 56 | 57 | Now let’s create a substrate to which we can later attach our monomers: 58 | 59 | .. code:: ipython3 60 | 61 | import mbuild as mb 62 | from mbuild.lib.surfaces import Betacristobalite 63 | 64 | surface = Betacristobalite() 65 | tiled_surface = mb.lib.recipes.TiledCompound(surface, n_tiles=(2, 1, 1)) 66 | 67 | Here we’ve imported a beta-cristobalite surface from our component 68 | library. The ``TiledCompound`` tool allows you replicate any 69 | ``Compound`` in the x-, y- and z-directions by any number of times - 2, 70 | 1 and 1 for our case. 71 | 72 | Next, let’s create our monomer and a hydrogen atom that we’ll place on 73 | unoccupied surface sites: 74 | 75 | .. code:: ipython3 76 | 77 | from mbuild.lib.atoms import H 78 | alkylsilane = AlkylSilane(chain_length=10) 79 | hydrogen = H() 80 | 81 | Then we need to tell mBuild how to arrange the chains on the surface. 82 | This is accomplished with the “pattern” tools. Every pattern is just a 83 | collection of points. There are all kinds of patterns like spherical, 84 | 2D, regular, irregular etc. When you use the ``apply_pattern`` command, 85 | you effectively superimpose the pattern onto the host compound, mBuild 86 | figures out what the closest ports are to the pattern points and then 87 | attaches copies of the guest onto the binding sites identified by the 88 | pattern: 89 | 90 | .. code:: ipython3 91 | 92 | pattern = mb.Grid2DPattern(8, 8) # Evenly spaced, 2D grid of points. 93 | 94 | # Attach chains to specified binding sites. Other sites get a hydrogen. 95 | chains, hydrogens = pattern.apply_to_compound(host=tiled_surface, guest=alkylsilane, backfill=hydrogen) 96 | 97 | Also note the ``backfill`` optional argument which allows you to place a 98 | different compound on any unused ports. In this case we want to backfill 99 | with hydrogen atoms on every port without a chain. 100 | 101 | .. code:: ipython3 102 | 103 | monolayer = mb.Compound([tiled_surface, chains, hydrogens]) 104 | monolayer.visualize() # Warning: may be slow in IPython notebooks 105 | 106 | .. code:: ipython3 107 | 108 | # Save as .mol2 file 109 | monolayer.save('monolayer.mol2', overwrite=True) 110 | 111 | ``lib.recipes.monolayer.py`` wraps many these functions into a simple, 112 | general class for generating the monolayers, as shown below: 113 | 114 | .. code:: ipython3 115 | 116 | from mbuild.lib.recipes import Monolayer 117 | 118 | monolayer = Monolayer(fractions=[1.0], chains=alkylsilane, backfill=hydrogen, 119 | pattern=mb.Grid2DPattern(n=8, m=8), 120 | surface=surface, tile_x=2, tile_y=1) 121 | monolayer.visualize() 122 | -------------------------------------------------------------------------------- /docs/getting_started/tutorials/tutorials.rst: -------------------------------------------------------------------------------- 1 | ----------------------- 2 | Tutorials 3 | ----------------------- 4 | .. only:: html 5 | 6 | The following tutorials are available either as html or interactive jupyter notebooks. 7 | 8 | 9 | .. toctree:: 10 | 11 | tutorial_methane 12 | tutorial_ethane 13 | tutorial_monolayer 14 | tutorial_simple_LJ 15 | tutorial_polymers 16 | tutorial_lattice 17 | -------------------------------------------------------------------------------- /docs/getting_started/writers/cassandra_file_writers.rst: -------------------------------------------------------------------------------- 1 | Cassandra File Writers 2 | =========================== 3 | 4 | .. automodule:: mbuild.formats.cassandramcf 5 | :members: 6 | -------------------------------------------------------------------------------- /docs/getting_started/writers/writers.rst: -------------------------------------------------------------------------------- 1 | ---------------------------------------------- 2 | File Writers 3 | ---------------------------------------------- 4 | 5 | The mBuild library also supports simulation engine-specific file writers. These writers create a complete set of simulation writers to input files or a partial set of file writers, where the other required files are generated via another means. 6 | 7 | mBuild utilizes ParmEd to write ``Compound`` information to a variety of file 8 | formats (e.g. PDB, MOL2, GRO. The full list of formats supported by ParmEd 9 | can be found at the `ParmEd website `_). 10 | Additionally, mBuild features several internal writers for file formats not yet 11 | supported by ParmEd. Information on these internal writers can be found below. 12 | 13 | By default, many mBuild functions will only write coordinate and bond information to these files, 14 | i.e. no angles or dihedrals, and no atom typing is performed (atom names are used 15 | as atom types). However, force fields can be applied to Compounds by passing force 16 | field XML files (used by the `Foyer package `_) 17 | to the ``Compound.save`` function if Foyer is installed. If a force field is applied to a 18 | Compound, the mBuild internal writers will also write angle and dihedral information 19 | to the file in addition to labelling atoms by the atom types specified by the force 20 | field. The CHARMM-style GOMC writers (supported through the `MoSDeF-GOMC extension `_) are the exception to this default rule since 21 | they need a force field to build the files, as these files depend on the force field parameters (Example: charge and MW in the PSF files). 22 | 23 | The simulation engine writers that use mBuild or are currently contained in the mBuild library: 24 | 25 | 26 | * `Cassandra `_ 27 | * `GROMACS `_ 28 | * `HOOMD-blue `_ 29 | * `Large-scale Atomic/Molecular Massively Parallel Simulator (LAMMPS) `_ 30 | 31 | Support for `GPU Optimized Monte Carlo (GOMC) `_ is also available through the `MoSDeF-GOMC library `_ 32 | 33 | .. toctree:: 34 | 35 | cassandra_file_writers 36 | -------------------------------------------------------------------------------- /docs/images/data_structures.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mosdef-hub/mbuild/8305c205a838fe1145acdd1450852542ef6926ec/docs/images/data_structures.png -------------------------------------------------------------------------------- /docs/images/lattice_BCC_CsCl_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mosdef-hub/mbuild/8305c205a838fe1145acdd1450852542ef6926ec/docs/images/lattice_BCC_CsCl_image.png -------------------------------------------------------------------------------- /docs/images/lattice_Diamond_cubic_Si_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mosdef-hub/mbuild/8305c205a838fe1145acdd1450852542ef6926ec/docs/images/lattice_Diamond_cubic_Si_image.png -------------------------------------------------------------------------------- /docs/images/lattice_FCC_Cu_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mosdef-hub/mbuild/8305c205a838fe1145acdd1450852542ef6926ec/docs/images/lattice_FCC_Cu_image.png -------------------------------------------------------------------------------- /docs/images/lattice_SC_polonium_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mosdef-hub/mbuild/8305c205a838fe1145acdd1450852542ef6926ec/docs/images/lattice_SC_polonium_image.png -------------------------------------------------------------------------------- /docs/images/lattice_graphene_2D_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mosdef-hub/mbuild/8305c205a838fe1145acdd1450852542ef6926ec/docs/images/lattice_graphene_2D_image.png -------------------------------------------------------------------------------- /docs/images/pmpc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mosdef-hub/mbuild/8305c205a838fe1145acdd1450852542ef6926ec/docs/images/pmpc.png -------------------------------------------------------------------------------- /docs/images/polymer_example_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mosdef-hub/mbuild/8305c205a838fe1145acdd1450852542ef6926ec/docs/images/polymer_example_image.png -------------------------------------------------------------------------------- /docs/images/polymer_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mosdef-hub/mbuild/8305c205a838fe1145acdd1450852542ef6926ec/docs/images/polymer_image.png -------------------------------------------------------------------------------- /docs/images/tnp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mosdef-hub/mbuild/8305c205a838fe1145acdd1450852542ef6926ec/docs/images/tnp.png -------------------------------------------------------------------------------- /docs/images/tnp_box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mosdef-hub/mbuild/8305c205a838fe1145acdd1450852542ef6926ec/docs/images/tnp_box.png -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | mBuild 2 | ======= 3 | 4 | .. image:: https://img.shields.io/badge/license-MIT-blue.svg 5 | :target: http://opensource.org/licenses/MIT 6 | 7 | *A hierarchical, component based molecule builder* 8 | 9 | With just a few lines of mBuild code, you can assemble reusable components into 10 | complex molecular systems for molecular simulations. 11 | 12 | 13 | * mBuild is designed to minimize or even eliminate the need to explicitly translate and 14 | orient components when building systems: you simply tell it to connect two 15 | pieces! 16 | * mBuild keeps track of the system's topology so you don't have to 17 | worry about manually defining bonds when constructing chemically bonded 18 | structures from smaller components. 19 | 20 | 21 | 22 | mBuild is a part of the MoSDeF ecosystem 23 | ---------------------------------------- 24 | 25 | The **mBuild** software, in conjunction with the other `Molecular Simulation Design Framework (MoSDeF) `_ tools, supports a wide range of 26 | simulation engines, including `Cassandra `_, `GPU Optimized Monte Carlo (GOMC) `_, `GROMACS `_, 27 | `HOOMD-blue `_, and 28 | `Large-scale Atomic/Molecular Massively Parallel Simulator (LAMMPS) `_. 29 | The **mBuild** and **MoSDeF** tools allow simulation reproducibility 30 | across the various simulation engines, eliminating the need to be an expert user in all 31 | the engines to replicate, continue, or advance the existing research. Additionally, 32 | the software can auto-generate many different systems, 33 | allowing large-scale screening of chemicals and materials using 34 | `Signac `_ to manage the simulations and data. 35 | 36 | The `MoSDeF `_ software is comprised the following packages: 37 | * `mBuild `_ -- A hierarchical, component based molecule builder 38 | * `foyer `_ -- A package for atom-typing as well as applying and disseminating forcefields 39 | * `GMSO `_ -- Flexible storage of chemical topology for molecular simulation 40 | 41 | 42 | .. toctree:: 43 | :caption: Getting Started 44 | :maxdepth: 2 45 | 46 | getting_started/example_system 47 | getting_started/installation/installation_toc 48 | getting_started/quick_start/quick_start 49 | getting_started/writers/writers 50 | getting_started/tutorials/tutorials 51 | 52 | .. toctree:: 53 | :caption: Topic Guides 54 | :maxdepth: 2 55 | 56 | topic_guides/recipe_development 57 | topic_guides/data_structures 58 | topic_guides/load_data 59 | topic_guides/coordinate_transforms 60 | topic_guides/recipes 61 | 62 | .. toctree:: 63 | :caption: Reference 64 | :maxdepth: 2 65 | 66 | reference/units 67 | reference/citing_mbuild 68 | reference/older_documentation 69 | -------------------------------------------------------------------------------- /docs/reference/citing_mbuild.rst: -------------------------------------------------------------------------------- 1 | ============= 2 | Citing mBuild 3 | ============= 4 | 5 | If you use mBuild for your research, please cite `our paper `_: 6 | 7 | **ACS** 8 | 9 | Klein, C.; Sallai, J.; Jones, T. J.; Iacovella, C. R.; McCabe, C.; Cummings, P. T. A Hierarchical, Component Based Approach to Screening Properties of Soft Matter. In *Foundations of Molecular Modeling and Simulation. Molecular Modeling and Simulation (Applications and Perspectives)*; Snurr, R. Q., Adjiman, C. S., Kofke, D. A., Eds.; Springer, Singapore, 2016; pp 79-92. 10 | 11 | **BibTeX** 12 | 13 | .. code-block:: bibtex 14 | 15 | @Inbook{Klein2016mBuild, 16 | author = "Klein, Christoph and Sallai, János and Jones, Trevor J. and Iacovella, Christopher R. and McCabe, Clare and Cummings, Peter T.", 17 | editor = "Snurr, Randall Q and Adjiman, Claire S. and Kofke, David A.", 18 | title = "A Hierarchical, Component Based Approach to Screening Properties of Soft Matter", 19 | bookTitle = "Foundations of Molecular Modeling and Simulation: Select Papers from FOMMS 2015", 20 | year = "2016", 21 | publisher = "Springer Singapore", 22 | address = "Singapore", 23 | pages = "79--92", 24 | isbn = "978-981-10-1128-3", 25 | doi = "10.1007/978-981-10-1128-3_5", 26 | url = "https://doi.org/10.1007/978-981-10-1128-3_5" 27 | } 28 | 29 | Download as :download:`BibTeX <../files/mbuild_citation.bib>` or :download:`RIS <../files/mbuild_citation.ris>` 30 | -------------------------------------------------------------------------------- /docs/reference/older_documentation.rst: -------------------------------------------------------------------------------- 1 | ==================== 2 | Older Documentation 3 | ==================== 4 | 5 | Up until `mBuild Version 0.10.4`_, the documentation is 6 | available as pdf files. Please use the following links to download the documentation as a pdf manual: 7 | 8 | * `Mbuild Version 0.10.4`_: `Download Here `__ 9 | * `Mbuild Version 0.10.3`_: `Download Here `__ 10 | * `Mbuild Version 0.10.1`_: `Download Here `__ 11 | * `Mbuild Version 0.9.3`_: `Download Here `__ 12 | 13 | 14 | .. _Mbuild Version 0.10.4: https://github.com/mosdef-hub/mbuild/releases/tag/0.10.4 15 | .. _Mbuild Version 0.10.3: https://github.com/mosdef-hub/mbuild/releases/tag/0.10.3 16 | .. _Mbuild Version 0.10.1: https://github.com/mosdef-hub/mbuild/releases/tag/0.10.1 17 | .. _Mbuild Version 0.9.3: https://github.com/mosdef-hub/mbuild/releases/tag/0.9.3 18 | -------------------------------------------------------------------------------- /docs/reference/units.rst: -------------------------------------------------------------------------------- 1 | ===== 2 | Units 3 | ===== 4 | 5 | mBuild automatically performs unit conversions in its reader and writer functions. 6 | When working with an :py:class:`mbuild.Compound`, mBuild uses the following units: 7 | 8 | +----------+----------+ 9 | | Quantity | Units | 10 | +==========+==========+ 11 | | distance | nm | 12 | +----------+----------+ 13 | | angle | radians* | 14 | +----------+----------+ 15 | 16 | \* :py:class:`mbuild.Lattice` and :py:class:`mbuild.Box` use degrees. 17 | 18 | See also `foyer unit documentation `_ and `ele documentation `_. 19 | -------------------------------------------------------------------------------- /docs/sphinxext/notebook_sphinxext.py: -------------------------------------------------------------------------------- 1 | # Copied from the mdtraj project, commit 3fddb5d (Mar 10, 2016) 2 | 3 | from __future__ import print_function 4 | 5 | import os 6 | import shutil 7 | 8 | import nbformat 9 | from docutils import nodes 10 | from docutils.parsers.rst import Directive, directives 11 | from nbconvert import HTMLExporter, PythonExporter 12 | 13 | 14 | def _read(wd, name): 15 | with open("{}/{}.ipynb".format(wd, name)) as f: 16 | notebook = nbformat.read(f, as_version=4) 17 | return notebook 18 | 19 | 20 | def export_html(wd, name): 21 | nb = _read(wd, name) 22 | 23 | config = { 24 | "Exporter": { 25 | "template_file": "embed", 26 | "template_path": ["./sphinxext/"], 27 | }, 28 | # 'ExecutePreprocessor': {'enabled': True}, 29 | "ExecutePreprocessor": {"enabled": False}, 30 | "ExtractOutputPreprocessor": {"enabled": True}, 31 | "CSSHTMLHeaderPreprocessor": {"enabled": True}, 32 | } 33 | 34 | exporter = HTMLExporter(config) 35 | 36 | try: 37 | body, resources = exporter.from_notebook_node(nb) 38 | 39 | for fn, data in resources["outputs"].items(): 40 | with open("{}/{}".format(wd, fn), "wb") as f: 41 | f.write(data) 42 | return body 43 | except Exception as e: 44 | return str(e) 45 | 46 | 47 | def export_python(wd, name): 48 | nb = _read(wd, name) 49 | exporter = PythonExporter() 50 | body, resources = exporter.from_notebook_node(nb) 51 | with open("{}/{}.py".format(wd, name), "w") as f: 52 | f.write(body) 53 | 54 | 55 | class NotebookDirective(Directive): 56 | """Insert an evaluated notebook into a document""" 57 | 58 | required_arguments = 1 59 | optional_arguments = 1 60 | option_spec = {"skip_exceptions": directives.flag} 61 | final_argument_whitespace = True 62 | 63 | def run(self): 64 | # check if raw html is supported 65 | if not self.state.document.settings.raw_enabled: 66 | raise self.warning('"%s" directive disabled.' % self.name) 67 | 68 | # get path to notebook 69 | nb_rel_path = self.arguments[0] 70 | nb_abs_path = "{}/../{}".format(setup.confdir, nb_rel_path) 71 | nb_abs_path = os.path.abspath(nb_abs_path) 72 | nb_name = os.path.basename(nb_rel_path).split(".")[0] 73 | dest_dir = "{}/{}/{}".format( 74 | setup.app.builder.outdir, os.path.dirname(nb_rel_path), nb_name 75 | ) 76 | fmt = {"wd": dest_dir, "name": nb_name} 77 | 78 | if not os.path.exists(dest_dir): 79 | os.makedirs(dest_dir) 80 | 81 | shutil.copyfile(nb_abs_path, "{wd}/{name}.ipynb".format(**fmt)) 82 | 83 | # TODO: Actually save evaluated notebook 84 | shutil.copyfile(nb_abs_path, "{wd}/{name}_eval.ipynb".format(**fmt)) 85 | 86 | html = export_html(**fmt) 87 | export_python(**fmt) 88 | 89 | # Create link to notebook and script files 90 | link_rst = "({uneval}; {eval}; {py})".format( 91 | uneval=formatted_link("{wd}/{name}.ipynb".format(**fmt)), 92 | eval=formatted_link("{wd}/{name}_eval.ipynb".format(**fmt)), 93 | py=formatted_link("{wd}/{name}.py".format(**fmt)), 94 | ) 95 | 96 | rst_file = self.state_machine.document.attributes["source"] 97 | self.state_machine.insert_input([link_rst], rst_file) 98 | 99 | # create notebook node 100 | attributes = {"format": "html", "source": "nb_path"} 101 | nb_node = notebook_node("", html, **attributes) 102 | nb_node.source, nb_node.line = self.state_machine.get_source_and_line( 103 | self.lineno 104 | ) 105 | 106 | # add dependency 107 | self.state.document.settings.record_dependencies.add(nb_abs_path) 108 | 109 | return [nb_node] 110 | 111 | 112 | class notebook_node(nodes.raw): 113 | pass 114 | 115 | 116 | def formatted_link(path): 117 | return "`%s <%s>`__" % (os.path.basename(path), path) 118 | 119 | 120 | def visit_notebook_node(self, node): 121 | self.visit_raw(node) 122 | 123 | 124 | def depart_notebook_node(self, node): 125 | self.depart_raw(node) 126 | 127 | 128 | def setup(app): 129 | setup.app = app 130 | setup.config = app.config 131 | setup.confdir = app.confdir 132 | 133 | app.add_node(notebook_node, html=(visit_notebook_node, depart_notebook_node)) 134 | 135 | app.add_directive("notebook", NotebookDirective) 136 | -------------------------------------------------------------------------------- /docs/topic_guides/coordinate_transforms.rst: -------------------------------------------------------------------------------- 1 | ========================== 2 | Coordinate Transformations 3 | ========================== 4 | The following utility functions provide mechanisms for spatial transformations for mbuild compounds: 5 | 6 | 7 | .. autofunction:: mbuild.coordinate_transform.force_overlap 8 | 9 | .. autofunction:: mbuild.coordinate_transform.x_axis_transform 10 | 11 | .. autofunction:: mbuild.coordinate_transform.y_axis_transform 12 | 13 | .. autofunction:: mbuild.coordinate_transform.z_axis_transform 14 | 15 | .. autofunction:: mbuild.compound.Compound.translate 16 | 17 | .. autofunction:: mbuild.compound.Compound.translate_to 18 | 19 | .. autofunction:: mbuild.compound.Compound.rotate 20 | 21 | .. autofunction:: mbuild.compound.Compound.spin 22 | -------------------------------------------------------------------------------- /docs/topic_guides/data_structures.rst: -------------------------------------------------------------------------------- 1 | =============== 2 | Data Structures 3 | =============== 4 | 5 | The primary building blocks in an mBuild hierarchy inherit from the 6 | :py:class:`mbuild.Compound` class. ``Compounds`` maintain an ordered set of ``children`` 7 | which are other ``Compounds``. In addition, an independent, ordered dictionary 8 | of ``labels`` is maintained through which users can reference any other 9 | ``Compound`` in the hierarchy via descriptive strings. Every ``Compound`` 10 | knows its parent ``Compound``, one step up in the hierarchy, and knows which 11 | ``Compounds`` reference it in their ``labels``. :py:class:`mbuild.Port` is a special type 12 | of ``Compound`` which are used internally to connect different ``Compounds`` 13 | using the equivalence transformations described below. 14 | 15 | ``Compounds`` at the bottom of an mBuild hierarchy, the leaves of the tree, are 16 | referred to as ``Particles`` and can be instantiated as ``foo = 17 | mbuild.Particle(name='bar')``. Note however, that this merely serves to illustrate 18 | that this ``Compound`` is at the bottom of the hierarchy; ``Particle`` is simply 19 | an alias for ``Compound`` which can be used to clarify the intended role of an 20 | object you are creating. The method :py:meth:`mbuild.Compound.particles` traverses the 21 | hierarchy to the bottom and yields those ``Compounds``. :py:meth:`mbuild.Compound.root` 22 | returns the compound at the top of the hierarchy. 23 | 24 | Compound 25 | -------- 26 | 27 | .. autoclass:: mbuild.Compound 28 | :members: 29 | 30 | 31 | Box 32 | --- 33 | 34 | .. autoclass:: mbuild.Box 35 | :members: 36 | 37 | Lattice 38 | ------- 39 | 40 | .. autoclass:: mbuild.Lattice 41 | :members: 42 | 43 | 44 | Port 45 | ---- 46 | 47 | .. autoclass:: mbuild.Port 48 | :members: 49 | -------------------------------------------------------------------------------- /docs/topic_guides/load_data.rst: -------------------------------------------------------------------------------- 1 | .. _loading_data: 2 | 3 | =============== 4 | Loading Data 5 | =============== 6 | 7 | Data is input into ``mBuild`` in a few different ways or from different file types. 8 | 9 | 10 | Load 11 | -------------------- 12 | 13 | .. automodule:: mbuild.conversion.load 14 | :members: 15 | 16 | 17 | Load CIF 18 | -------------------- 19 | 20 | .. automodule:: mbuild.lattice.load_cif 21 | :members: 22 | -------------------------------------------------------------------------------- /docs/topic_guides/recipes.rst: -------------------------------------------------------------------------------- 1 | Recipes 2 | ======= 3 | 4 | Monolayer 5 | --------- 6 | 7 | .. autoclass:: mbuild.lib.recipes.monolayer.Monolayer 8 | :members: 9 | 10 | Polymer 11 | ------- 12 | 13 | .. autoclass:: mbuild.lib.recipes.polymer.Polymer 14 | :members: 15 | 16 | Tiled Compound 17 | -------------- 18 | 19 | .. autoclass:: mbuild.lib.recipes.tiled_compound.TiledCompound 20 | :members: 21 | 22 | Silica Interface 23 | ---------------- 24 | 25 | .. autoclass:: mbuild.lib.recipes.silica_interface.SilicaInterface 26 | :members: 27 | 28 | Packing 29 | ------- 30 | .. automodule:: mbuild.packing 31 | :members: 32 | 33 | Pattern 34 | ------- 35 | .. automodule:: mbuild.pattern 36 | :members: 37 | -------------------------------------------------------------------------------- /environment-dev.yml: -------------------------------------------------------------------------------- 1 | name: mbuild-dev 2 | channels: 3 | - conda-forge 4 | dependencies: 5 | - python>=3.9,<=3.12 6 | - boltons 7 | - numpy=1.26.4 8 | - sympy 9 | - unyt>=2.9.5 10 | - boltons 11 | - lark>=1.2 12 | - lxml 13 | - freud>=3.0 14 | - intermol 15 | - mdtraj 16 | - pydantic>=2 17 | - networkx 18 | - nglview>=3 19 | - pytest 20 | - garnett>=0.7.1 21 | - openbabel>=3.0.0 22 | - openff-toolkit-base >=0.11,<0.16.7 23 | - openmm 24 | - gsd>=2.9 25 | - parmed>=3.4.3 26 | - packmol>=20.15 27 | - pytest-cov 28 | - pycifrw 29 | - rdkit>=2021 30 | - requests 31 | - requests-mock 32 | - scipy 33 | - treelib 34 | - codecov 35 | - matplotlib 36 | - ipywidgets 37 | - ele>=0.2.0 38 | - pre-commit 39 | - pandas 40 | - symengine 41 | - python-symengine 42 | - hoomd>=4.0,<5.0 43 | - importlib_resources 44 | - pip: 45 | - git+https://github.com/mosdef-hub/gmso.git@main 46 | - git+https://github.com/mosdef-hub/foyer.git@main 47 | - git+https://github.com/mosdef-hub/forcefield-utilities.git@main 48 | -------------------------------------------------------------------------------- /environment.yml: -------------------------------------------------------------------------------- 1 | name: mbuild 2 | channels: 3 | - conda-forge 4 | dependencies: 5 | - ele 6 | - numpy=1.26.4 7 | - packmol>=20.15 8 | - gmso>=0.9.0 9 | - garnett 10 | - parmed>=3.4.3 11 | - pycifrw 12 | - python>=3.8 13 | - rdkit>=2021 14 | - scipy 15 | - networkx 16 | - treelib 17 | - importlib_resources 18 | -------------------------------------------------------------------------------- /mbuild/__init__.py: -------------------------------------------------------------------------------- 1 | # ruff: noqa: F401 2 | # ruff: noqa: F403 3 | """mBuild: a hierarchical, component based molecule builder.""" 4 | 5 | from mbuild.box import Box 6 | from mbuild.coarse_graining import coarse_grain 7 | from mbuild.compound import * 8 | from mbuild.conversion import load 9 | from mbuild.coordinate_transform import * 10 | from mbuild.lattice import Lattice 11 | from mbuild.packing import * 12 | from mbuild.pattern import * 13 | from mbuild.port import Port 14 | from mbuild.recipes import recipes 15 | 16 | __version__ = "1.1.1" 17 | __date__ = "2025-01-23" 18 | -------------------------------------------------------------------------------- /mbuild/bond_graph.py: -------------------------------------------------------------------------------- 1 | """Bond graph for mBuild Compounds. 2 | 3 | NOTE: The functions 'connected_components' and '_bfs' have been obtained (with 4 | modifications) from the Networkx Python package, which is distributed under the 5 | following BSD license: 6 | 7 | Copyright (C) 2004-2016, NetworkX Developers 8 | Aric Hagberg 9 | Dan Schult 10 | Pieter Swart 11 | All rights reserved. 12 | 13 | Redistribution and use in source and binary forms, with or without 14 | modification, are permitted provided that the following conditions are 15 | met: 16 | 17 | * Redistributions of source code must retain the above copyright 18 | notice, this list of conditions and the following disclaimer. 19 | 20 | * Redistributions in binary form must reproduce the above 21 | copyright notice, this list of conditions and the following 22 | disclaimer in the documentation and/or other materials provided 23 | with the distribution. 24 | 25 | * Neither the name of the NetworkX Developers nor the names of its 26 | contributors may be used to endorse or promote products derived 27 | from this software without specific prior written permission. 28 | 29 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 30 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 31 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 32 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 33 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 34 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 35 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 36 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 37 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 38 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 39 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40 | """ 41 | 42 | import networkx as nx 43 | 44 | 45 | class BondGraph(nx.Graph): 46 | """Subclasses nx.Graph to store connectivity information.""" 47 | 48 | def _bfs(self, source): 49 | seen = set() 50 | nextlevel = {source} 51 | while nextlevel: 52 | thislevel = nextlevel 53 | nextlevel = set() 54 | for v in thislevel: 55 | if v not in seen: 56 | yield v 57 | seen.add(v) 58 | nextlevel.update(self.neighbors(v)) 59 | 60 | def connected_components(self): 61 | """Return list of connected bond component of bondgraph.""" 62 | return [list(mol) for mol in nx.connected_components(self)] 63 | -------------------------------------------------------------------------------- /mbuild/exceptions.py: -------------------------------------------------------------------------------- 1 | """mBuild specific exceptions.""" 2 | 3 | 4 | class MBuildError(Exception): 5 | """Base class for all non-trivial errors raised by mBuild.""" 6 | -------------------------------------------------------------------------------- /mbuild/formats/README.txt: -------------------------------------------------------------------------------- 1 | This directory is temporary and serves as a staging ground for file writers 2 | currently not supported by Parmed. 3 | -------------------------------------------------------------------------------- /mbuild/formats/__init__.py: -------------------------------------------------------------------------------- 1 | """Format library for mBuild.""" 2 | -------------------------------------------------------------------------------- /mbuild/formats/compound.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | message Vec3 { 4 | // A generic 3-tuple, could be used for positions or periodicities 5 | float x = 1; 6 | float y = 2; 7 | float z = 3; 8 | } 9 | 10 | message Vec2 { 11 | // A generic 2-tuple, could be used for compound-id pairs 12 | int64 id1 = 1; 13 | int64 id2 = 2; 14 | } 15 | 16 | message Element { 17 | string name = 1; 18 | string symbol = 2; 19 | int64 atomic_number = 3; 20 | float mass = 4; 21 | } 22 | 23 | message Compound { 24 | string name = 1; 25 | repeated Compound children = 2; 26 | Vec3 pos = 3; 27 | Vec3 periodicity = 4; 28 | float charge = 5; 29 | int64 id = 6; // this is simply a unique number for this compound 30 | repeated Vec2 bonds = 7; // a list of 2-tuples 31 | Element element = 8; 32 | } 33 | -------------------------------------------------------------------------------- /mbuild/lib/__init__.py: -------------------------------------------------------------------------------- 1 | """Library of structures for mBuild.""" 2 | -------------------------------------------------------------------------------- /mbuild/lib/atoms/__init__.py: -------------------------------------------------------------------------------- 1 | # ruff: noqa: F401 2 | """mBuild library of atoms.""" 3 | 4 | from mbuild.lib.atoms.c3 import C3 5 | from mbuild.lib.atoms.h import H 6 | from mbuild.lib.atoms.n4 import N4 7 | -------------------------------------------------------------------------------- /mbuild/lib/atoms/c3.py: -------------------------------------------------------------------------------- 1 | """A tri-valent, planar carbon atom.""" 2 | 3 | import numpy as np 4 | 5 | import mbuild as mb 6 | 7 | 8 | class C3(mb.Compound): 9 | """A tri-valent, planar carbon.""" 10 | 11 | def __init__(self): 12 | super(C3, self).__init__() 13 | self.add(mb.Particle(name="C", element="C")) 14 | 15 | self.add(mb.Port(anchor=self[0]), "up") 16 | self["up"].translate(np.array([0, 0.07, 0])) 17 | 18 | self.add(mb.Port(anchor=self[0]), "down") 19 | self["down"].translate(np.array([0, 0.07, 0])) 20 | self["down"].spin(np.pi * 2 / 3, [0, 0, 1]) 21 | 22 | self.add(mb.Port(anchor=self[0]), "left") 23 | self["left"].translate(np.array([0, 0.07, 0])) 24 | self["left"].spin(-np.pi * 2 / 3, [0, 0, 1]) 25 | 26 | 27 | if __name__ == "__main__": 28 | m = C3() 29 | m.save("c3.mol2", overwrite=True) 30 | -------------------------------------------------------------------------------- /mbuild/lib/atoms/h.py: -------------------------------------------------------------------------------- 1 | """An H atom.""" 2 | 3 | import numpy as np 4 | 5 | import mbuild as mb 6 | 7 | 8 | class H(mb.Compound): 9 | """A hydrogen atom with two overlaid ports.""" 10 | 11 | def __init__(self): 12 | super(H, self).__init__() 13 | self.add(mb.Particle(name="H", element="H")) 14 | self.add(mb.Port(anchor=self[0]), "up") 15 | self["up"].spin(np.pi, [0, 0, 1]) 16 | self["up"].translate(np.array([0, 0.07, 0])) 17 | 18 | 19 | if __name__ == "__main__": 20 | m = H() 21 | m.save("h.mol2", overwrite=True) 22 | -------------------------------------------------------------------------------- /mbuild/lib/atoms/n4.py: -------------------------------------------------------------------------------- 1 | """mBuild atom library for tetravalent nitrogen.""" 2 | 3 | import numpy as np 4 | 5 | import mbuild as mb 6 | 7 | 8 | class N4(mb.Compound): 9 | """A tetravalent nitrogen atom.""" 10 | 11 | def __init__(self): 12 | super(N4, self).__init__() 13 | self.add(mb.Particle(name="N", pos=[0, 0, 0], element="N"), label="N[$]") 14 | self.add(mb.Port(anchor=self[0]), label="port_0") 15 | self.add(mb.Port(anchor=self[0]), label="port_1") 16 | self.add(mb.Port(anchor=self[0]), label="port_2") 17 | self.add(mb.Port(anchor=self[0]), label="port_3") 18 | 19 | self["port_2"].spin(2 / 3 * np.pi, [1, 0, 0]) 20 | self["port_3"].spin(-2 / 3 * np.pi, [1, 0, 0]) 21 | self["port_1"].spin(1 / 3 * np.pi, [0, 0, 1]) 22 | self["port_2"].spin(-1 / 3 * np.pi, [0, 0, 1]) 23 | self["port_3"].spin(-1 / 3 * np.pi, [0, 0, 1]) 24 | 25 | self["port_0"].translate([0, 0.073, 0]) 26 | self["port_1"].translate([0.0594, -0.0243, 0]) 27 | self["port_2"].translate([-0.042, -0.0243, 0.042]) 28 | self["port_3"].translate([-0.042, -0.0243, -0.042]) 29 | 30 | 31 | if __name__ == "__main__": 32 | m = N4() 33 | m.save("n4.mol2", overwrite=True) 34 | -------------------------------------------------------------------------------- /mbuild/lib/bulk_materials/__init__.py: -------------------------------------------------------------------------------- 1 | # ruff: noqa: F401 2 | """mBuild bulk materials library.""" 3 | 4 | from mbuild.lib.bulk_materials.amorphous_silica_bulk import AmorphousSilicaBulk 5 | -------------------------------------------------------------------------------- /mbuild/lib/bulk_materials/amorphous_silica_bulk.py: -------------------------------------------------------------------------------- 1 | """A bulk structure of amorphous silica.""" 2 | 3 | import mbuild as mb 4 | 5 | 6 | class AmorphousSilicaBulk(mb.Compound): 7 | """An amorphous silica box. 8 | 9 | density 2.2g/cm^3 10 | """ 11 | 12 | def __init__(self): 13 | super(AmorphousSilicaBulk, self).__init__() 14 | 15 | mb.load( 16 | "amorphous_silica_bulk.pdb", 17 | compound=self, 18 | relative_to_module=self.__module__, 19 | ) 20 | self.box = mb.Box([5, 5, 5]) 21 | self.periodicity = (True, True, True) 22 | 23 | 24 | if __name__ == "__main__": 25 | bulk = AmorphousSilicaBulk() 26 | bulk.save("bulk.mol2") 27 | -------------------------------------------------------------------------------- /mbuild/lib/moieties/__init__.py: -------------------------------------------------------------------------------- 1 | # ruff: noqa: F401 2 | """mBuild library of common chemical moieties.""" 3 | 4 | from mbuild.lib.moieties.ch2 import CH2 5 | from mbuild.lib.moieties.ch3 import CH3 6 | from mbuild.lib.moieties.ester import Ester 7 | from mbuild.lib.moieties.h2o import H2O 8 | from mbuild.lib.moieties.silane import Silane 9 | -------------------------------------------------------------------------------- /mbuild/lib/moieties/ch2.pdb: -------------------------------------------------------------------------------- 1 | COMPND UNNAMED 2 | AUTHOR GENERATED BY OPEN BABEL 3 | ATOM 1 C LIG A 1 0.000 0.000 0.000 1.00 0.00 C 4 | ATOM 2 H LIG A 1 -1.100 0.000 0.000 1.00 0.00 H 5 | ATOM 3 H LIG A 1 1.100 0.000 0.000 1.00 0.00 H 6 | CONECT 1 2 3 7 | CONECT 2 1 8 | CONECT 3 1 9 | MASTER 0 0 0 0 0 0 0 0 3 0 3 0 10 | END 11 | -------------------------------------------------------------------------------- /mbuild/lib/moieties/ch2.py: -------------------------------------------------------------------------------- 1 | """CH2 moiety.""" 2 | 3 | import mbuild as mb 4 | 5 | 6 | class CH2(mb.Compound): 7 | """A methylene bridge.""" 8 | 9 | def __init__(self): 10 | super(CH2, self).__init__() 11 | 12 | mb.load( 13 | "ch2.pdb", 14 | compound=self, 15 | relative_to_module=self.__module__, 16 | infer_hierarchy=False, 17 | ) 18 | self.translate(-self[0].pos) # Move carbon to origin. 19 | 20 | self.add(mb.Port(anchor=self[0]), "up") 21 | self["up"].translate([0, 0.07, 0]) 22 | 23 | self.add(mb.Port(anchor=self[0], orientation=[0, -1, 0]), "down") 24 | self["down"].translate([0, -0.07, 0]) 25 | 26 | 27 | if __name__ == "__main__": 28 | ch2 = CH2() 29 | ch2.save("ch2.mol2") 30 | -------------------------------------------------------------------------------- /mbuild/lib/moieties/ch3.pdb: -------------------------------------------------------------------------------- 1 | COMPND UNNAMED 2 | AUTHOR GENERATED BY OPEN BABEL 3 | ATOM 1 C LIG A 1 -1.750 1.662 0.000 1.00 0.00 C 4 | ATOM 2 H LIG A 1 -0.680 1.662 0.000 1.00 0.00 H 5 | ATOM 3 H LIG A 1 -2.107 2.431 0.653 1.00 0.00 H 6 | ATOM 4 H LIG A 1 -2.107 1.843 -0.993 1.00 0.00 H 7 | CONECT 1 2 3 4 8 | CONECT 2 1 9 | CONECT 3 1 10 | CONECT 4 1 11 | MASTER 0 0 0 0 0 0 0 0 4 0 4 0 12 | END 13 | -------------------------------------------------------------------------------- /mbuild/lib/moieties/ch3.py: -------------------------------------------------------------------------------- 1 | """mBuild CH3 moiety.""" 2 | 3 | import mbuild as mb 4 | 5 | 6 | class CH3(mb.Compound): 7 | """A methyl group.""" 8 | 9 | def __init__(self): 10 | super(CH3, self).__init__() 11 | 12 | mb.load( 13 | "ch3.pdb", 14 | compound=self, 15 | relative_to_module=self.__module__, 16 | infer_hierarchy=False, 17 | ) 18 | self.translate(-self[0].pos) # Move carbon to origin. 19 | 20 | self.add(mb.Port(anchor=self[0]), "up") 21 | self["up"].translate([0, -0.07, 0]) 22 | 23 | 24 | if __name__ == "__main__": 25 | m = CH3() 26 | m.save("ch3.mol2", overwrite=True) 27 | -------------------------------------------------------------------------------- /mbuild/lib/moieties/ester.pdb: -------------------------------------------------------------------------------- 1 | COMPND UNNAMED 2 | AUTHOR GENERATED BY OPEN BABEL 3 | HETATM 1 C LIG 1 -0.948 0.666 0.000 1.00 0.00 C 4 | HETATM 2 O LIG 1 -0.984 2.161 -0.000 1.00 0.00 O 5 | HETATM 3 O LIG 1 0.231 -0.050 0.000 1.00 0.00 O 6 | CONECT 1 2 3 7 | CONECT 2 1 8 | CONECT 3 1 9 | MASTER 0 0 0 0 0 0 0 0 3 0 3 0 10 | END 11 | -------------------------------------------------------------------------------- /mbuild/lib/moieties/ester.py: -------------------------------------------------------------------------------- 1 | """Ester moiety.""" 2 | 3 | import numpy as np 4 | 5 | import mbuild as mb 6 | 7 | 8 | class Ester(mb.Compound): 9 | """A ester group -C(=O)O-.""" 10 | 11 | def __init__(self): 12 | super(Ester, self).__init__() 13 | 14 | mb.load( 15 | "ester.pdb", 16 | compound=self, 17 | relative_to_module=self.__module__, 18 | infer_hierarchy=False, 19 | ) 20 | self.translate(-self[0].pos) 21 | 22 | self.add(mb.Port(anchor=self[2]), "up") 23 | self["up"].spin(np.pi / 2, [0, 0, 1]) 24 | self["up"].translate_to(np.array([0.07, 0, 0])) 25 | 26 | self.add(mb.Port(anchor=self[0]), "down") 27 | self["down"].spin(np.pi / 2, [0, 0, 1]) 28 | self["down"].translate(np.array([-0.07, 0, 0])) 29 | 30 | 31 | if __name__ == "__main__": 32 | m = Ester() 33 | m.save("ester.mol2", overwrite=True) 34 | -------------------------------------------------------------------------------- /mbuild/lib/moieties/h2o.py: -------------------------------------------------------------------------------- 1 | """A water molecule.""" 2 | 3 | import mbuild as mb 4 | 5 | 6 | class H2O(mb.Compound): 7 | """A water molecule.""" 8 | 9 | def __init__(self): 10 | super(H2O, self).__init__() 11 | 12 | self.add(mb.Particle(name="O", pos=[1.0203, 0.7604, 1.2673], element="O")) 13 | self.add(mb.Particle(name="H", pos=[0.9626, 0.8420, 1.2673], element="H")) 14 | self.add(mb.Particle(name="H", pos=[0.9626, 0.6787, 1.2673], element="H")) 15 | self.add_bond((self[0], self[1])) 16 | self.add_bond((self[0], self[2])) 17 | 18 | 19 | if __name__ == "__main__": 20 | m = H2O() 21 | m.save("h2o.mol2") 22 | -------------------------------------------------------------------------------- /mbuild/lib/moieties/peg.py: -------------------------------------------------------------------------------- 1 | """mBuild polyethylene glycol (PEG) monomer moiety.""" 2 | 3 | __author__ = "jonestj1" 4 | 5 | import mbuild as mb 6 | 7 | 8 | class PegMonomer(mb.Compound): 9 | """A monomer of polyethylene glycol (PEG).""" 10 | 11 | def __init__(self): 12 | super(PegMonomer, self).__init__() 13 | 14 | mb.load( 15 | "peg_monomer.pdb", 16 | compound=self, 17 | relative_to_module=self.__module__, 18 | infer_hierarchy=False, 19 | ) 20 | self.translate(-self[0].pos) 21 | 22 | self.add(mb.Port(anchor=self[0]), "down") 23 | self["down"].translate([0, -0.07, 0]) 24 | 25 | self.add(mb.Port(anchor=self[6]), "up") 26 | self["up"].translate([0, 0.073, 0]) 27 | 28 | 29 | if __name__ == "__main__": 30 | peg = PegMonomer() 31 | peg.save("peg.mol2") 32 | -------------------------------------------------------------------------------- /mbuild/lib/moieties/peg_monomer.pdb: -------------------------------------------------------------------------------- 1 | COMPND UNNAMED 2 | AUTHOR GENERATED BY OPEN BABEL 3 | HETATM 1 C LIG 1 0.000 0.000 0.000 1.00 0.00 C 4 | HETATM 2 H LIG 1 -1.400 0.000 0.000 1.00 0.00 H 5 | HETATM 3 H LIG 1 1.400 0.000 0.000 1.00 0.00 H 6 | HETATM 4 C LIG 1 0.000 1.540 0.000 1.00 0.00 C 7 | HETATM 5 H LIG 1 -1.400 1.540 0.000 1.00 0.00 H 8 | HETATM 6 H LIG 1 1.400 1.540 0.000 1.00 0.00 H 9 | HETATM 7 O LIG 1 0.000 2.970 0.000 1.00 0.00 O 10 | CONECT 1 2 3 4 11 | CONECT 2 1 12 | CONECT 3 1 13 | CONECT 4 1 5 6 7 14 | CONECT 4 15 | CONECT 5 4 16 | CONECT 6 4 17 | CONECT 7 4 18 | MASTER 0 0 0 0 0 0 0 0 7 0 7 0 19 | END 20 | -------------------------------------------------------------------------------- /mbuild/lib/moieties/silane.pdb: -------------------------------------------------------------------------------- 1 | COMPND UNNAMED 2 | AUTHOR GENERATED BY OPEN BABEL 3 | ATOM 1 Si LIG A 1 1.379 0.507 0.000 1.00 0.00 Si 4 | ATOM 2 O LIG A 1 0.079 0.645 0.000 1.00 0.00 O 5 | ATOM 3 H LIG A 1 -0.243 0.711 0.671 1.00 0.00 H 6 | ATOM 4 O LIG A 1 2.837 0.504 0.000 1.00 0.00 O 7 | ATOM 5 H LIG A 1 3.194 0.383 -0.802 1.00 0.00 H 8 | CONECT 1 2 4 9 | CONECT 2 1 3 10 | CONECT 3 2 11 | CONECT 4 1 5 12 | CONECT 5 4 13 | MASTER 0 0 0 0 0 0 0 0 5 0 5 0 14 | END 15 | -------------------------------------------------------------------------------- /mbuild/lib/moieties/silane.py: -------------------------------------------------------------------------------- 1 | """A Silane (Si(OH)2) moiety.""" 2 | 3 | import numpy as np 4 | 5 | import mbuild as mb 6 | 7 | 8 | class Silane(mb.Compound): 9 | """An Si(OH)2 group with two ports.""" 10 | 11 | def __init__( 12 | self, 13 | ): 14 | super(Silane, self).__init__() 15 | mb.load( 16 | "silane.pdb", 17 | compound=self, 18 | relative_to_module=self.__module__, 19 | infer_hierarchy=False, 20 | backend="parmed", 21 | skip_bonds=True, 22 | ) 23 | 24 | # Transform the coordinate system such that the silicon atom is at the 25 | # origin and the oxygen atoms are on the x axis. 26 | mb.x_axis_transform(self, new_origin=self[0], point_on_x_axis=self[1]) 27 | 28 | # Add bottom port. 29 | self.add(mb.Port(anchor=self[0]), "down") 30 | self["down"].translate(np.array([0, -0.07, 0])) 31 | 32 | # Add top port. 33 | self.add(mb.Port(anchor=self[0]), "up") 34 | self["up"].translate(np.array([0, 0.07, 0])) 35 | 36 | 37 | if __name__ == "__main__": 38 | m = Silane() 39 | m.save("silane.mol2") 40 | -------------------------------------------------------------------------------- /mbuild/lib/molecules/__init__.py: -------------------------------------------------------------------------------- 1 | # ruff: noqa: F401 2 | """Library of molecules for mBuild.""" 3 | 4 | from mbuild.lib.molecules.ethane import Ethane 5 | from mbuild.lib.molecules.methane import Methane 6 | from mbuild.lib.molecules.water import ( 7 | WaterSPC, 8 | WaterTIP3P, 9 | WaterTIP4P, 10 | WaterTIP4P2005, 11 | WaterTIP4PIce, 12 | ) 13 | -------------------------------------------------------------------------------- /mbuild/lib/molecules/ethane.py: -------------------------------------------------------------------------------- 1 | """An ethane molecule.""" 2 | 3 | import mbuild as mb 4 | from mbuild.lib.moieties import CH3 5 | 6 | 7 | class Ethane(mb.Compound): 8 | """An ethane molecule. 9 | 10 | Connect two methyl groups to form an ethane. 11 | """ 12 | 13 | def __init__(self): 14 | super(Ethane, self).__init__() 15 | 16 | self.add(CH3(), "methyl1") 17 | self.add(CH3(), "methyl2") 18 | mb.force_overlap(self["methyl1"], self["methyl1"]["up"], self["methyl2"]["up"]) 19 | -------------------------------------------------------------------------------- /mbuild/lib/molecules/methane.py: -------------------------------------------------------------------------------- 1 | """A methane molecule.""" 2 | 3 | import mbuild as mb 4 | 5 | 6 | class Methane(mb.Compound): 7 | """A methane molecule.""" 8 | 9 | def __init__(self): 10 | super(Methane, self).__init__() 11 | carbon = mb.Particle(name="C", element="C") 12 | self.add(carbon) 13 | 14 | hydrogen = mb.Particle(name="H", pos=[0.1, 0, -0.07], element="H") 15 | self.add(hydrogen) 16 | 17 | self.add_bond((self[0], self[1])) 18 | 19 | self.add(mb.Particle(name="H", pos=[-0.1, 0, -0.07], element="H")) 20 | self.add(mb.Particle(name="H", pos=[0, 0.1, 0.07], element="H")) 21 | self.add(mb.Particle(name="H", pos=[0, -0.1, 0.07], element="H")) 22 | 23 | self.add_bond((self[0], self[2])) 24 | self.add_bond((self[0], self[3])) 25 | self.add_bond((self[0], self[4])) 26 | -------------------------------------------------------------------------------- /mbuild/lib/molecules/water.py: -------------------------------------------------------------------------------- 1 | """Water molecules with geometries from different models.""" 2 | 3 | import numpy as np 4 | 5 | import mbuild as mb 6 | 7 | 8 | class Water3Site(mb.Compound): 9 | """A generic 3-site water model.""" 10 | 11 | def __init__(self, oh_bond_length, hoh_angle): 12 | super().__init__() 13 | 14 | o1 = mb.Compound(name="OW", element="O", pos=[0.0, 0.0, 0.0]) 15 | h1 = mb.Compound(name="HW1", element="H", pos=[oh_bond_length, 0.0, 0.0]) 16 | h2 = mb.Compound( 17 | name="HW2", 18 | element="H", 19 | pos=[ 20 | oh_bond_length * np.cos(np.radians(hoh_angle)), 21 | oh_bond_length * np.sin(np.radians(180.0 - hoh_angle)), 22 | 0.0, 23 | ], 24 | ) 25 | 26 | self.add([o1, h1, h2]) 27 | self.add_bond([o1, h1]) 28 | self.add_bond([o1, h2]) 29 | 30 | 31 | class WaterTIP3P(Water3Site): 32 | """A TIP3P water molecule. 33 | 34 | Paper: https://doi.org/10.1063/1.445869 35 | Additional reference: https://lammps.sandia.gov/doc/Howto_tip3p.html 36 | """ 37 | 38 | def __init__(self): 39 | oh_bond_length = 0.09572 # nm 40 | hoh_angle = 104.52 # deg 41 | super().__init__(oh_bond_length, hoh_angle) 42 | 43 | 44 | class WaterSPC(Water3Site): 45 | """An SPC water molecule. 46 | 47 | Paper: https://doi.org/10.1021/j100308a038 48 | Additional reference: https://lammps.sandia.gov/doc/Howto_spc.html 49 | """ 50 | 51 | def __init__(self): 52 | oh_bond_length = 0.1 # nm 53 | hoh_angle = 109.47 # deg 54 | super().__init__(oh_bond_length, hoh_angle) 55 | 56 | 57 | class Water4Site(mb.Compound): 58 | """A generic 4-site water model.""" 59 | 60 | def __init__(self, oh_bond_length, hoh_angle, om_bond_length): 61 | super().__init__() 62 | 63 | o1 = mb.Compound(name="OW", element="O", pos=[0.0, 0.0, 0.0]) 64 | h1 = mb.Compound(name="HW1", element="H", pos=[oh_bond_length, 0.0, 0.0]) 65 | h2 = mb.Compound( 66 | name="HW2", 67 | element="H", 68 | pos=[ 69 | oh_bond_length * np.cos(np.radians(hoh_angle)), 70 | oh_bond_length * np.sin(np.radians(180.0 - hoh_angle)), 71 | 0.0, 72 | ], 73 | ) 74 | m1 = mb.Compound( 75 | name="MW", 76 | element=None, 77 | pos=[ 78 | om_bond_length * np.cos(np.radians(hoh_angle / 2.0)), 79 | om_bond_length * np.sin(np.radians(hoh_angle / 2.0)), 80 | 0.0, 81 | ], 82 | ) 83 | 84 | self.add([o1, h1, h2, m1]) 85 | self.add_bond([o1, h1]) 86 | self.add_bond([o1, h2]) 87 | 88 | 89 | class WaterTIP4P(Water4Site): 90 | """A TIP4P water molecule. 91 | 92 | Paper: https://doi.org/10.1063/1.445869 93 | Additional reference: https://lammps.sandia.gov/doc/Howto_tip4p.html 94 | """ 95 | 96 | def __init__(self): 97 | oh_bond_length = 0.09572 # nm 98 | om_bond_length = 0.015 # nm 99 | hoh_angle = 104.52 # deg 100 | super().__init__(oh_bond_length, hoh_angle, om_bond_length) 101 | 102 | 103 | class WaterTIP4PIce(Water4Site): 104 | """A TIP4P/Ice water molecule. 105 | 106 | Paper: https://doi.org/10.1063/1.1931662 107 | Additional reference: https://lammps.sandia.gov/doc/Howto_tip4p.html 108 | """ 109 | 110 | def __init__(self): 111 | oh_bond_length = 0.09572 # nm 112 | om_bond_length = 0.01577 # nm 113 | hoh_angle = 104.52 # deg 114 | super().__init__(oh_bond_length, hoh_angle, om_bond_length) 115 | 116 | 117 | class WaterTIP4P2005(Water4Site): 118 | """A TIP4P/2005 water molecule. 119 | 120 | Paper: https://doi.org/10.1063/1.2121687 121 | Additional reference: https://lammps.sandia.gov/doc/Howto_tip4p.html 122 | """ 123 | 124 | def __init__(self): 125 | oh_bond_length = 0.09572 # nm 126 | om_bond_length = 0.01546 # nm 127 | hoh_angle = 104.52 # deg 128 | super().__init__(oh_bond_length, hoh_angle, om_bond_length) 129 | -------------------------------------------------------------------------------- /mbuild/lib/recipes/__init__.py: -------------------------------------------------------------------------------- 1 | # ruff: noqa: F401 2 | """Library of recipes for mBuild.""" 3 | 4 | from mbuild.lib.recipes.alkane import Alkane 5 | from mbuild.lib.recipes.monolayer import Monolayer 6 | from mbuild.lib.recipes.polymer import Polymer 7 | from mbuild.lib.recipes.silica_interface import SilicaInterface 8 | from mbuild.lib.recipes.tiled_compound import TiledCompound 9 | -------------------------------------------------------------------------------- /mbuild/lib/recipes/alkane.py: -------------------------------------------------------------------------------- 1 | """mBuild recipe for a generic alkane chain.""" 2 | 3 | import mbuild as mb 4 | from mbuild.lib.moieties import CH2, CH3 5 | from mbuild.lib.molecules import Ethane, Methane 6 | 7 | 8 | class Alkane(mb.Compound): 9 | """An alkane which may optionally end with a hydrogen or a Port.""" 10 | 11 | def __init__(self, n=3, cap_front=True, cap_end=True): 12 | """Initialize an Alkane Compound. 13 | 14 | Args 15 | ---- 16 | n: int, default 3, 17 | Number of carbon atoms. 18 | cap_front: bool, default True 19 | Whether to add a methyl group to the beginning of chain 20 | ('down' port). 21 | cap_end: bool, default True, 22 | Whether to add a methyl group to the end of chain ('up' port). 23 | """ 24 | if n < 1: 25 | raise ValueError("n must be 1 or more") 26 | super(Alkane, self).__init__() 27 | from mbuild.lib.recipes import Polymer 28 | 29 | # Handle the case of Methane and Ethane separately 30 | if n < 3: 31 | if n == 1: 32 | if cap_front and cap_end: 33 | self.add(Methane(), "chain") 34 | elif cap_front != cap_end: 35 | chain = CH3() 36 | self.add(chain, "chain") 37 | if cap_front: 38 | self.add(chain["up"], "down", containment=False) 39 | else: 40 | self.add(chain["up"], "up", containment=False) 41 | else: 42 | chain = CH2() 43 | self.add(chain) 44 | self.add(chain["down"], "down", containment=False) 45 | self.add(chain["up"], "up", containment=False) 46 | elif n == 2: 47 | if cap_front and cap_end: 48 | self.add(Ethane(), "chain") 49 | elif cap_front != cap_end: 50 | chain = CH2() 51 | self.add(chain, "chain") 52 | if cap_front: 53 | self.add(CH3(), "methyl_front") 54 | mb.force_overlap( 55 | move_this=self["chain"], 56 | from_positions=self["chain"]["up"], 57 | to_positions=self["methyl_front"]["up"], 58 | ) 59 | self.add(chain["down"], "down", containment=False) 60 | else: 61 | self.add(CH3(), "methyl_end") 62 | mb.force_overlap( 63 | self["methyl_end"], 64 | self["methyl_end"]["up"], 65 | self["chain"]["down"], 66 | ) 67 | self.add(chain["up"], "up", containment=False) 68 | else: 69 | chain = Polymer(monomers=[CH2()]) 70 | chain.build(2, add_hydrogens=False) 71 | self.add(chain, "chain") 72 | self.add(chain["down"], "down", containment=False) 73 | self.add(chain["up"], "up", containment=False) 74 | 75 | # Handle general case of n >= 3 76 | else: 77 | end_groups = [None, None] 78 | # Adjust length of Polmyer for absence of methyl terminations. 79 | if cap_front: 80 | n -= 1 81 | end_groups[0] = CH3() 82 | if cap_end: 83 | n -= 1 84 | end_groups[1] = CH3() 85 | 86 | chain = Polymer(monomers=[CH2()], end_groups=end_groups) 87 | chain.build(n, add_hydrogens=False) 88 | self.add(chain, "chain") 89 | if not cap_front: 90 | # Hoist port label to Alkane level. 91 | self.add(self["chain"]["up"], "up", containment=False) 92 | if not cap_end: 93 | # Hoist port label to Alkane level. 94 | self.add(self["chain"]["down"], "down", containment=False) 95 | -------------------------------------------------------------------------------- /mbuild/lib/recipes/monolayer.py: -------------------------------------------------------------------------------- 1 | """mBuild monolayer recipe.""" 2 | 3 | from copy import deepcopy 4 | from warnings import warn 5 | 6 | import numpy as np 7 | 8 | import mbuild as mb 9 | 10 | __all__ = ["Monolayer"] 11 | 12 | 13 | class Monolayer(mb.Compound): 14 | """A general monolayer recipe. 15 | 16 | Parameters 17 | ---------- 18 | surface : mb.Compound 19 | Surface on which the monolayer will be built. 20 | chains : list of mb.Compounds 21 | The chains to be replicated and attached to the surface. 22 | fractions : list of floats 23 | The fractions of the pattern to be allocated to each chain. 24 | backfill : list of mb.Compound, optional, default=None 25 | If there are fewer chains than there are ports on the surface, 26 | copies of `backfill` will be used to fill the remaining ports. 27 | pattern : mb.Pattern, optional, default=mb.Random2DPattern 28 | An array of planar binding locations. If not provided, the entire 29 | surface will be filled with `chain`. 30 | tile_x : int, optional, default=1 31 | Number of times to replicate substrate in x-direction. 32 | tile_y : int, optional, default=1 33 | Number of times to replicate substrate in y-direction. 34 | 35 | """ 36 | 37 | def __init__( 38 | self, 39 | surface, 40 | chains, 41 | fractions=None, 42 | backfill=None, 43 | pattern=None, 44 | tile_x=1, 45 | tile_y=1, 46 | **kwargs, 47 | ): 48 | from mbuild.lib.recipes import TiledCompound 49 | 50 | super(Monolayer, self).__init__() 51 | 52 | # Replicate the surface. 53 | tiled_compound = TiledCompound(surface, n_tiles=(tile_x, tile_y, 1)) 54 | self.add(tiled_compound, label="tiled_surface") 55 | 56 | if pattern is None: # Fill the surface. 57 | pattern = mb.Random2DPattern(len(tiled_compound.referenced_ports())) 58 | 59 | if isinstance(chains, mb.Compound): 60 | chains = [chains] 61 | 62 | if fractions: 63 | fractions = list(fractions) 64 | if len(chains) != len(fractions): 65 | raise ValueError( 66 | "Number of fractions does not match the number" 67 | " of chain types provided" 68 | ) 69 | 70 | n_chains = len(pattern.points) 71 | 72 | # Attach chains of each type to binding sites based on 73 | # respective fractions. 74 | for chain, fraction in zip(chains[:-1], fractions[:-1]): 75 | # Create sub-pattern for this chain type 76 | subpattern = deepcopy(pattern) 77 | n_points = int(round(fraction * n_chains)) 78 | warn("\n Adding {} of chain {}".format(n_points, chain)) 79 | pick = np.random.choice( 80 | subpattern.points.shape[0], n_points, replace=False 81 | ) 82 | points = subpattern.points[pick] 83 | subpattern.points = points 84 | 85 | # Remove now-occupied points from overall pattern 86 | pattern.points = np.array( 87 | [ 88 | point 89 | for point in pattern.points.tolist() 90 | if point not in subpattern.points.tolist() 91 | ] 92 | ) 93 | 94 | # Attach chains to the surface 95 | attached_chains, _ = subpattern.apply_to_compound( 96 | guest=chain, host=self["tiled_surface"], backfill=None, **kwargs 97 | ) 98 | self.add(attached_chains) 99 | 100 | else: 101 | warn("\n No fractions provided. Assuming a single chain type.") 102 | 103 | # Attach final chain type. Remaining sites get a backfill. 104 | warn("\n Adding {} of chain {}".format(len(pattern), chains[-1])) 105 | attached_chains, backfills = pattern.apply_to_compound( 106 | guest=chains[-1], host=self["tiled_surface"], backfill=backfill, **kwargs 107 | ) 108 | self.add(attached_chains) 109 | self.add(backfills) 110 | -------------------------------------------------------------------------------- /mbuild/lib/surfaces/__init__.py: -------------------------------------------------------------------------------- 1 | # ruff: noqa: F401 2 | """mBuild surface library.""" 3 | 4 | from mbuild.lib.surfaces.amorphous_silica_surface import AmorphousSilicaSurface 5 | from mbuild.lib.surfaces.betacristobalite import Betacristobalite 6 | -------------------------------------------------------------------------------- /mbuild/lib/surfaces/amorphous_silica_surface.py: -------------------------------------------------------------------------------- 1 | """Amorphous silica surface.""" 2 | 3 | import mbuild as mb 4 | 5 | 6 | class AmorphousSilicaSurface(mb.Compound): 7 | """Amorphous silica surface.""" 8 | 9 | def __init__(self, surface_roughness=1.0): 10 | super(AmorphousSilicaSurface, self).__init__() 11 | 12 | if surface_roughness == 1.0: 13 | mb.load( 14 | "amorphous_silica_sr1.0.pdb", 15 | compound=self, 16 | relative_to_module=self.__module__, 17 | ) 18 | self.periodicity = (True, True, False) 19 | self.box = mb.Box([5.4366, 4.7082, 1.0]) 20 | else: 21 | raise ValueError( 22 | "Amorphous silica input file with surface " 23 | "roughness of {0:.1f} does not exist. If you have " 24 | "this structure, please submit a pull request to " 25 | "add it! ".format(surface_roughness) 26 | ) 27 | count = 0 28 | for particle in list(self.particles()): 29 | if particle.name == "OB": 30 | count += 1 31 | port = mb.Port(anchor=particle, orientation=[0, 0, 1], separation=0.1) 32 | self.add(port, "port_{}".format(count)) 33 | 34 | 35 | if __name__ == "__main__": 36 | from mbuild.lib.recipes import TiledCompound 37 | 38 | single = AmorphousSilicaSurface() 39 | multiple = TiledCompound(single, n_tiles=(2, 1, 1), name="tiled") 40 | multiple.save("amorphous_silica_surface.mol2") 41 | -------------------------------------------------------------------------------- /mbuild/lib/surfaces/betacristobalite.py: -------------------------------------------------------------------------------- 1 | """Beta-cristobalite surface.""" 2 | 3 | import mbuild as mb 4 | 5 | 6 | class Betacristobalite(mb.Compound): 7 | """The beta-cristobalite form of SiO2. 8 | 9 | Area per port specifies the density of attachment sites in nm^2. 10 | The crystal is expanded to yield an area per port of 0.25 nm^2, the 11 | typical density of alkane monolayers on SiO2 although these are actually 12 | grown on amorphous SiO2 in experiment. 13 | 14 | See http://www.wikiwand.com/en/Silicon_dioxide for more info on the various 15 | crystal forms. 16 | 17 | Note: Port sites are currently naively determined by placing them on all 18 | oxygens which are above 1.0 nm in the z-direction. This only holds true for 19 | the beta-cristobalite-expanded.mol2 file. If you add a new one, please 20 | modify the file or the method of determining port locations. 21 | """ 22 | 23 | def __init__(self): 24 | super(Betacristobalite, self).__init__() 25 | 26 | mb.load( 27 | "beta-cristobalite-expanded.mol2", 28 | compound=self, 29 | relative_to_module=self.__module__, 30 | backend="gmso", 31 | ) 32 | self.periodicity = (True, True, False) 33 | # 1.3200 taken from boundingbox length rounded to 4 decimal places 34 | self.box = mb.Box([5.3888, 4.6669, 1.3200]) 35 | 36 | count = 0 37 | for particle in list(self.particles()): 38 | if particle.name.startswith("O") and particle.pos[2] > 1.0: 39 | count += 1 40 | port = mb.Port(anchor=particle, orientation=[0, 0, 1], separation=0.1) 41 | self.add(port, "port_{}".format(count)) 42 | particle.name = "O" # Strip numbers required in .mol2 files. 43 | elif particle.name.startswith("Si"): 44 | particle.name = "Si" 45 | 46 | 47 | if __name__ == "__main__": 48 | single = Betacristobalite() 49 | multiple = mb.recipes.TiledCompound(single, n_tiles=(2, 1, 1), name="tiled") 50 | multiple.save("betacristobalite.mol2", overwrite=True) 51 | -------------------------------------------------------------------------------- /mbuild/recipes/__init__.py: -------------------------------------------------------------------------------- 1 | """Entrypoints for mBuild recipe plugins.""" 2 | 3 | import sys 4 | from importlib import metadata 5 | 6 | 7 | class Recipes(object): 8 | """mBuild recipe object.""" 9 | 10 | pass 11 | 12 | 13 | recipes = Recipes() 14 | 15 | if sys.version_info.minor >= 10: 16 | entry_points = metadata.entry_points().select(group="mbuild.plugins") 17 | else: 18 | entry_points = metadata.entry_points()["mbuild.plugins"] 19 | 20 | available_methods = [] 21 | for entry_point in entry_points: 22 | setattr(recipes, entry_point.name, entry_point.load()) 23 | -------------------------------------------------------------------------------- /mbuild/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mosdef-hub/mbuild/8305c205a838fe1145acdd1450852542ef6926ec/mbuild/tests/__init__.py -------------------------------------------------------------------------------- /mbuild/tests/test_coarse_graining.py: -------------------------------------------------------------------------------- 1 | import mbuild as mb 2 | from mbuild.tests.base_test import BaseTest 3 | 4 | 5 | class TestCoarseGraining(BaseTest): 6 | def test_hexane(self, hexane, propyl): 7 | particles = [propyl.__class__] 8 | cg = mb.coarse_grain(hexane, particle_classes=particles) 9 | assert cg.n_particles == 2 10 | assert cg.n_bonds == 1 11 | assert all(child.name.startswith(propyl.name) for child in cg.children) 12 | 13 | cg_clone = mb.clone(cg) 14 | assert cg_clone.n_particles == 2 15 | assert cg_clone.n_bonds == 1 16 | assert all(child.name.startswith(propyl.name) for child in cg_clone.children) 17 | assert cg_clone.wrapped.n_particles == 20 18 | assert cg_clone.wrapped.n_bonds == 19 19 | -------------------------------------------------------------------------------- /mbuild/tests/test_gmso.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pytest 3 | 4 | import mbuild as mb 5 | from mbuild.conversion import from_gmso 6 | from mbuild.tests.base_test import BaseTest 7 | from mbuild.utils.io import has_gmso, import_ 8 | 9 | if has_gmso: 10 | gmso = import_("gmso") 11 | 12 | 13 | @pytest.mark.skipif(not has_gmso, reason="GMSO is not installed") 14 | class TestGMSO(BaseTest): 15 | def test_to_gmso(self, ethane): 16 | gmso_eth = ethane.to_gmso() # Equivalent to to_gmso(ethane) 17 | 18 | assert isinstance(gmso_eth, gmso.Topology) 19 | assert len(gmso_eth.bonds) == ethane.n_bonds 20 | for i in range(ethane.n_particles): 21 | assert ethane[i].name == gmso_eth.sites[i].name 22 | assert np.isclose(ethane[i].xyz, gmso_eth.sites[i].position.value).all() 23 | 24 | def test_full_conversion(self, ethane): 25 | # Note: at this point, the full conversion may lose some information regarding the hierarchical, 26 | # especially, if the original compound has more than 3 layers. 27 | gmso_eth = ethane.to_gmso() 28 | mb_eth = from_gmso(gmso_eth) 29 | 30 | assert mb_eth.n_particles == ethane.n_particles 31 | assert mb_eth.n_bonds == ethane.n_bonds 32 | for i in range(mb_eth.n_particles): 33 | assert mb_eth[i].name == ethane[i].name 34 | assert np.isclose(mb_eth[i].xyz, ethane[i].xyz).all() 35 | 36 | def test_coords_only(self, ethane): 37 | gmso_eth = ethane.to_gmso() 38 | mb_eth = from_gmso(gmso_eth) 39 | # Reset coord of the mb_eth 40 | for particle in mb_eth.particles(): 41 | particle.xyz = [[0, 0, 0]] 42 | 43 | mb_eth.from_gmso(gmso_eth, coords_only=True) 44 | for i in range(mb_eth.n_particles): 45 | assert np.isclose(mb_eth[i].xyz, ethane[i].xyz).all() 46 | 47 | def test_mismatch_coords_only(self, ethane): 48 | gmso_eth = ethane.to_gmso() 49 | meth = mb.load("C", smiles=True) 50 | with pytest.raises(ValueError): 51 | meth.from_gmso(gmso_eth, coords_only=True) 52 | 53 | def test_infer_hier(selfs, ethane): 54 | # Create an ethane box, should be a four structure 55 | eth_box = mb.packing.fill_box(compound=ethane, n_compounds=1, density=1) 56 | 57 | # don't infer_hierarchy, parse_label=False 58 | unlabeled_top = eth_box.to_gmso(parse_label=False) 59 | for site in unlabeled_top.sites: 60 | assert not site.residue or site.molecule or site.group 61 | 62 | # infer_hierarchy 63 | labeled_top = eth_box.to_gmso(parse_label=True) 64 | for site in labeled_top.sites: 65 | assert site.group == "Ethane" 66 | assert site.molecule.name == "Ethane" 67 | assert site.residue.name == "CH3" 68 | -------------------------------------------------------------------------------- /mbuild/tests/test_lib_molecule.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pytest 3 | 4 | from mbuild.lib.molecules import ( 5 | WaterSPC, 6 | WaterTIP3P, 7 | WaterTIP4P, 8 | WaterTIP4P2005, 9 | WaterTIP4PIce, 10 | ) 11 | from mbuild.tests.base_test import BaseTest 12 | 13 | 14 | class TestWater(BaseTest): 15 | @pytest.mark.parametrize( 16 | "model, bond_length, angle", 17 | [(WaterTIP3P, 0.09572, 104.52), (WaterSPC, 0.1, 109.47)], 18 | ) 19 | def test_water_3site(self, model, bond_length, angle): 20 | water = model() 21 | o1 = [p for p in water.particles_by_name("OW")] 22 | assert len(o1) == 1 23 | o1 = o1[0] 24 | h1 = [p for p in water.particles_by_name("HW1")] 25 | assert len(h1) == 1 26 | h1 = h1[0] 27 | h2 = [p for p in water.particles_by_name("HW2")] 28 | assert len(h2) == 1 29 | h2 = h2[0] 30 | v1 = h1.xyz[0] - o1.xyz[0] 31 | v2 = h2.xyz[0] - o1.xyz[0] 32 | assert np.allclose(np.linalg.norm(v1), bond_length) 33 | assert np.allclose(np.linalg.norm(v2), bond_length) 34 | assert np.allclose( 35 | np.degrees( 36 | np.arccos(np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2))) 37 | ), 38 | angle, 39 | ) 40 | 41 | @pytest.mark.parametrize( 42 | "model, bond_length, vsite_length, angle", 43 | [ 44 | (WaterTIP4P, 0.09572, 0.015, 104.52), 45 | (WaterTIP4PIce, 0.09572, 0.01577, 104.52), 46 | (WaterTIP4P2005, 0.09572, 0.01546, 104.52), 47 | ], 48 | ) 49 | def test_water_4site(self, model, bond_length, vsite_length, angle): 50 | water = model() 51 | o1 = [p for p in water.particles_by_name("OW")] 52 | assert len(o1) == 1 53 | o1 = o1[0] 54 | h1 = [p for p in water.particles_by_name("HW1")] 55 | assert len(h1) == 1 56 | h1 = h1[0] 57 | h2 = [p for p in water.particles_by_name("HW2")] 58 | assert len(h2) == 1 59 | h2 = h2[0] 60 | m1 = [p for p in water.particles_by_name("MW")] 61 | assert len(m1) == 1 62 | m1 = m1[0] 63 | v1 = h1.xyz[0] - o1.xyz[0] 64 | v2 = h2.xyz[0] - o1.xyz[0] 65 | v3 = m1.xyz[0] - o1.xyz[0] 66 | assert np.allclose(np.linalg.norm(v1), bond_length) 67 | assert np.allclose(np.linalg.norm(v2), bond_length) 68 | assert np.allclose(np.linalg.norm(v3), vsite_length) 69 | assert np.allclose( 70 | np.degrees( 71 | np.arccos(np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2))) 72 | ), 73 | angle, 74 | ) 75 | -------------------------------------------------------------------------------- /mbuild/tests/test_mol2file.py: -------------------------------------------------------------------------------- 1 | import mbuild as mb 2 | from mbuild.lib.moieties import CH3 3 | from mbuild.tests.base_test import BaseTest 4 | from mbuild.utils.io import get_fn 5 | 6 | 7 | class TestMol2(BaseTest): 8 | def test_load_and_create(self): 9 | mb.load(get_fn("methyl.mol2")) 10 | 11 | def test_update_coordinates(self): 12 | methyl = CH3() 13 | methyl.update_coordinates(get_fn("methyl.mol2")) 14 | 15 | def test_save(self): 16 | methyl = mb.load(get_fn("methyl.mol2")) 17 | methyl.save(filename="methyl_out.mol2") 18 | 19 | def test_gmso_backend(self): 20 | pmd_silica_surface = mb.load( 21 | filename_or_object=get_fn("beta-cristobalite-expanded.mol2"), 22 | backend="parmed", 23 | ) 24 | gmso_silica_surface = mb.load( 25 | filename_or_object=get_fn("beta-cristobalite-expanded.mol2"), 26 | backend="gmso", 27 | ) 28 | 29 | assert pmd_silica_surface.n_particles == gmso_silica_surface.n_particles 30 | assert pmd_silica_surface.n_bonds == gmso_silica_surface.n_bonds 31 | 32 | element_set = set() 33 | for particle in gmso_silica_surface: 34 | element_set.add(particle.element) 35 | assert len(element_set) == 2 36 | 37 | def test_gmso_backend_lj_site_type(self): 38 | pmd_silica_surface = mb.load( 39 | filename_or_object=get_fn("beta-cristobalite-expanded.mol2"), 40 | backend="parmed", 41 | ) 42 | gmso_silica_surface = mb.load( 43 | filename_or_object=get_fn("beta-cristobalite-expanded.mol2"), 44 | backend="gmso", 45 | site_type="lj", 46 | ) 47 | 48 | assert pmd_silica_surface.n_particles == gmso_silica_surface.n_particles 49 | assert pmd_silica_surface.n_bonds == gmso_silica_surface.n_bonds 50 | 51 | for particle in gmso_silica_surface: 52 | assert particle.element is None 53 | -------------------------------------------------------------------------------- /mbuild/tests/test_monolayer.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | import mbuild as mb 4 | from mbuild.lib.atoms import H 5 | from mbuild.lib.recipes import Monolayer, Polymer 6 | from mbuild.lib.surfaces import Betacristobalite 7 | from mbuild.tests.base_test import BaseTest 8 | 9 | 10 | class TestMonolayer(BaseTest): 11 | def test_monolayer(self, ch2): 12 | n = 8 13 | m = 8 14 | pattern = mb.Grid2DPattern(n, m) 15 | 16 | chain = Polymer(monomers=[ch2]) 17 | chain.build(n=10, add_hydrogens=False) 18 | monolayer = Monolayer( 19 | surface=Betacristobalite(), 20 | chains=chain, 21 | backfill=H(), 22 | pattern=pattern, 23 | ) 24 | 25 | assert monolayer.n_particles == 2000 + n * m * 29 26 | assert monolayer.n_bonds == 2500 + n * m * 29 27 | 28 | def test_pattern_kwargs(self, ch2): 29 | n = 8 30 | m = 8 31 | pattern = mb.Grid2DPattern(n, m) 32 | 33 | chain = Polymer(monomers=[ch2]) 34 | chain.build(n=10, add_hydrogens=False) 35 | 36 | monolayer = Monolayer( 37 | surface=Betacristobalite(), 38 | chains=H(), 39 | guest_port_name="up", 40 | backfill=chain, 41 | backfill_port_name="down", 42 | pattern=pattern, 43 | ) 44 | 45 | chains = 100 - (n * m) 46 | 47 | assert monolayer.n_particles == 2000 + chains * 29 48 | assert monolayer.n_bonds == 2500 + chains * 29 49 | 50 | def test_periodic_pattern(self, ch2): 51 | # Make Periodic without Hydrogen Conflict 52 | for axis in ["x", "y", "z"]: 53 | chain = Polymer(monomers=[ch2]) 54 | chain.build(n=10, add_hydrogens=False) 55 | chain.create_periodic_bond(axis=axis) 56 | assert not chain.all_ports() 57 | 58 | bonded_atoms = [x.name for x in list(chain["monomer[0]"][0].direct_bonds())] 59 | assert bonded_atoms.count("H") == 2 60 | assert bonded_atoms.count("C") == 2 61 | 62 | # Make Periodic with Hydrogen Conflict 63 | chain2 = Polymer(monomers=[ch2]) 64 | chain2.build(n=10, add_hydrogens=True) 65 | with pytest.raises(ValueError): 66 | chain2.create_periodic_bond(axis="y") 67 | 68 | # Make Periodic with End-Group Conflict 69 | chain3 = Polymer(monomers=[ch2], end_groups=[mb.clone(ch2), mb.clone(ch2)]) 70 | chain3.build(n=10) 71 | with pytest.raises(ValueError): 72 | chain3.create_periodic_bond(axis="z") 73 | 74 | # Make Periodic with Unsupported Axis 75 | chain2 = Polymer(monomers=[ch2]) 76 | chain2.build(n=10, add_hydrogens=True) 77 | with pytest.raises(ValueError): 78 | chain2.create_periodic_bond(axis="a") 79 | 80 | def test_mixed_monolayer(self, ch2): 81 | n = 8 82 | m = 8 83 | pattern = mb.Grid2DPattern(n, m) 84 | fractions = [0.75, 0.25] 85 | 86 | chain_a = Polymer(monomers=[ch2]) 87 | chain_a.build(n=5, add_hydrogens=False) 88 | 89 | chain_b = Polymer(monomers=[ch2]) 90 | chain_b.build(n=15, add_hydrogens=False) 91 | 92 | monolayer = Monolayer( 93 | surface=Betacristobalite(), 94 | chains=[chain_a, chain_b], 95 | fractions=fractions, 96 | backfill=H(), 97 | pattern=pattern, 98 | ) 99 | 100 | n_a = round(n * m * 0.75) 101 | n_b = round(n * m * 0.25) 102 | assert monolayer.n_particles == 2000 + n_a * 14 + n_b * 44 103 | assert monolayer.n_bonds == 2500 + n_a * 14 + n_b * 44 104 | -------------------------------------------------------------------------------- /mbuild/tests/test_plugins.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from mbuild.tests.base_test import BaseTest 4 | 5 | 6 | class TestPlugins(BaseTest): 7 | def test_basic_import(self): 8 | pass 9 | 10 | @pytest.mark.parametrize( 11 | "recipe_name", 12 | ["Monolayer", "Polymer", "SilicaInterface", "TiledCompound"], 13 | ) 14 | def test_recipes_contents(self, recipe_name): 15 | import mbuild.recipes 16 | 17 | recipe_name in dir(mbuild.recipes) 18 | -------------------------------------------------------------------------------- /mbuild/tests/test_polymer.py: -------------------------------------------------------------------------------- 1 | import os 2 | from collections import Counter 3 | 4 | import pytest 5 | 6 | import mbuild as mb 7 | from mbuild.lib.recipes import Polymer 8 | from mbuild.tests.base_test import BaseTest 9 | 10 | 11 | class TestPolymer(BaseTest): 12 | def test_polymer_from_smiles(self): 13 | chain = Polymer() 14 | ethane = mb.load("CC", smiles=True) 15 | chain.add_monomer(ethane, indices=[2, -2], separation=0.15, replace=True) 16 | chain.build(n=5, add_hydrogens=True) 17 | assert len([p for p in chain.particles() if p.name == "C"]) == 10 18 | assert len([p for p in chain.particles() if p.name == "H"]) == 22 19 | assert len(chain.available_ports()) == 0 20 | assert len(chain.children) == 5 21 | 22 | def test_add_end_groups(self, ch2, ester): 23 | n = 6 24 | c6 = Polymer(monomers=[ch2]) 25 | acid = mb.load("C(=O)O", smiles=True) 26 | c6.add_end_groups(acid, index=3, separation=0.15) 27 | c6.build(n=n, add_hydrogens=False) 28 | assert len([p for p in c6.particles() if p.name == "O"]) == 4 29 | 30 | def test_pass_end_groups(self, ch2, ester): 31 | ester_2 = mb.clone(ester) 32 | c6 = Polymer(monomers=[ch2], end_groups=[ester, ester_2]) 33 | c6.build(n=6) 34 | assert c6.children[-1].name == "Ester" 35 | assert c6.children[-2].name == "Ester" 36 | 37 | def test_errors(self, ch2, ester): 38 | with pytest.raises(ValueError): # Not enough end groups 39 | Polymer(monomers=[ch2], end_groups=[ester]) 40 | 41 | with pytest.raises(ValueError): # Bad sequence 42 | chain = Polymer(monomers=[ch2]) 43 | chain.build(n=5, sequence="AB") 44 | 45 | with pytest.raises(ValueError): # Bad n value 46 | chain = Polymer(monomers=[ch2]) 47 | chain.build(n=0, sequence="A") 48 | 49 | with pytest.raises(ValueError): # Bad end group label 50 | chain = Polymer(monomers=[ch2]) 51 | acid = mb.load("C(=O)O", smiles=True) 52 | chain.add_end_groups( 53 | acid, index=3, separation=0.15, duplicate=False, label="front" 54 | ) 55 | 56 | def test_no_end_groups(self): 57 | chain = Polymer() 58 | ethane = mb.load("CC", smiles=True) 59 | chain.add_monomer(ethane, indices=[2, -2], separation=0.15, replace=True) 60 | chain.build(n=5, add_hydrogens=False) 61 | assert len([p for p in chain.particles() if p.name == "H"]) == 20 62 | assert len(chain.available_ports()) == 2 63 | 64 | def test_replace_is_false(self): 65 | n = 6 66 | ch2 = mb.load(os.path.join(mb.__path__[0], "lib/moieties/ch2.pdb")) 67 | chain = Polymer() 68 | chain.add_monomer( 69 | ch2, 70 | indices=[0, 0], 71 | orientation=[[0, 1, 0], [0, -1, 0]], 72 | separation=0.15, 73 | replace=False, 74 | ) 75 | chain.build(n=n, add_hydrogens=False) 76 | assert chain.n_particles == n * 3 77 | assert chain.n_bonds == n * 2 + (n - 1) 78 | 79 | def test_polymer_from_moieties(self, ch2): 80 | n = 6 81 | c6 = Polymer(monomers=[ch2]) 82 | c6.build(n=n, add_hydrogens=False) 83 | assert c6.n_particles == n * 3 84 | assert c6.n_bonds == n * 2 + (n - 1) 85 | 86 | def test_block_copolymer(self, ch2, ester): 87 | n = 2 88 | sequence = "ABBA" 89 | abba = Polymer(monomers=[ch2, ester]) 90 | abba.build(n=n, sequence=sequence, add_hydrogens=False) 91 | 92 | assert abba.n_particles == n * 3 * len(sequence) 93 | assert len(abba.children) == len(sequence) * n 94 | assert abba.children[0].name == "CH2" 95 | assert abba.children[1].name == "Ester" 96 | assert abba.children[2].name == "Ester" 97 | assert abba.children[3].name == "CH2" 98 | assert abba.children[4].name == "CH2" 99 | assert abba.children[5].name == "Ester" 100 | assert abba.children[6].name == "Ester" 101 | assert abba.children[7].name == "CH2" 102 | n_elements = Counter(p.name for p in abba.particles()) 103 | assert n_elements["C"] == n * len(sequence) 104 | assert n_elements["H"] == n * len(sequence) 105 | assert n_elements["O"] == n * len(sequence) 106 | assert abba.n_bonds == n * 2 * len(sequence) + (n * len(sequence) - 1) 107 | -------------------------------------------------------------------------------- /mbuild/tests/test_port.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pytest 3 | 4 | import mbuild as mb 5 | from mbuild.tests.base_test import BaseTest 6 | 7 | 8 | class TestPattern(BaseTest): 9 | def test_port_center(self): 10 | port = mb.Port() 11 | assert [round(coord, 3) == 0 for coord in port.center] 12 | 13 | def test_port_shift(self, ethane): 14 | ethane.translate_to(np.ones(3)) 15 | port = mb.Port(anchor=ethane) 16 | assert [ethane.center[i] == coord for i, coord in enumerate(port.center)] 17 | 18 | def test_port_init_shift_0(self, ethane): 19 | ethane.translate_to(np.ones(3)) 20 | port = mb.Port(anchor=ethane, separation=0) 21 | assert [ethane.center[i] == coord for i, coord in enumerate(port.center)] 22 | 23 | def test_port_init_shift(self, ethane): 24 | ethane.translate_to(np.ones(3)) 25 | separation = [1, 2, 3] 26 | port = mb.Port(anchor=ethane, separation=separation) 27 | assert [ 28 | ethane.center[i] + separation[i] == coord 29 | for i, (coord, sep) in enumerate(zip(port.center, separation)) 30 | ] 31 | 32 | def test_port_init_rotate_0(self, ethane): 33 | port1 = mb.Port(anchor=ethane, orientation=[0, 1, 0]) 34 | port2 = mb.Port(anchor=ethane) 35 | assert np.allclose(port1.xyz_with_ports, port2.xyz_with_ports, atol=1e-15) 36 | 37 | def test_port_init_rotate(self, ethane): 38 | port1 = mb.Port(anchor=ethane, orientation=[1, 1, 1]) 39 | port2 = mb.Port(anchor=ethane) 40 | assert not np.allclose(port1.xyz_with_ports, port2.xyz_with_ports, atol=1e-15) 41 | 42 | def test_port_init_rotate_180(self, ethane): 43 | port1 = mb.Port(anchor=ethane, orientation=[0, -1, 0]) 44 | port2 = mb.Port(anchor=ethane) 45 | assert not np.allclose(port1.xyz_with_ports, port2.xyz_with_ports, atol=1e-15) 46 | 47 | def test_port_direction(self): 48 | port = mb.Port() 49 | assert np.allclose([0, 1, 0], port.direction, atol=1e-16) 50 | port.rotate(np.pi, [1, 0, 0]) 51 | assert np.allclose([0, -1, 0], port.direction, atol=1e-15) 52 | 53 | def test_port_separation(self, ethane): 54 | port = mb.Port(anchor=ethane, separation=0.7) 55 | assert np.allclose(0.7, port.separation, atol=1e-15) 56 | 57 | port_no_anchor = mb.Port() 58 | with pytest.warns(UserWarning): 59 | separation = port_no_anchor.separation 60 | assert separation is None 61 | 62 | def test_update_separation(self, ethane, hexane): 63 | port = mb.Port(anchor=ethane, separation=0.7) 64 | port.update_separation(separation=0.9) 65 | assert np.allclose(0.9, port.separation, atol=1e-15) 66 | 67 | port_used = hexane.labels["propyl2"].labels["down"] 68 | with pytest.warns(UserWarning): 69 | port_used.update_separation(0.10) 70 | 71 | def test_update_orientaiton(self, ch2, hexane): 72 | port = ch2["up"] 73 | port.update_orientation(orientation=(1, 0, 0)) 74 | assert np.allclose([-1, 0, 0], port.direction, atol=1e-15) 75 | 76 | port_used = hexane.labels["propyl2"].labels["down"] 77 | with pytest.warns(UserWarning): 78 | port_used.update_orientation([0, 1, 0]) 79 | 80 | def test_access_labels(self): 81 | port = mb.Port() 82 | compound = mb.Compound() 83 | compound.add(port, label="foo") 84 | assert port.access_labels == {"['foo']"} 85 | 86 | compound2 = mb.Compound(name="C2") 87 | compound2.add(compound, label="bar") 88 | assert port.access_labels == {"['bar']['foo']"} 89 | 90 | def test_up_down_reverse_orientation_axes(self): 91 | for vector in [[1, 0, 0], [0, 1, 0], [0, 0, 1]]: 92 | port1 = mb.Port(orientation=vector) 93 | port2 = mb.Port(orientation=-np.array(vector)) 94 | assert np.allclose(port1["up"].xyz_with_ports, port2["down"].xyz_with_ports) 95 | assert np.allclose(port1["down"].xyz_with_ports, port2["up"].xyz_with_ports) 96 | 97 | def test_up_down_reverse_orientation_random(self): 98 | np.random.seed(84) 99 | for _ in range(15): 100 | vector = np.random.random(3) - 0.5 101 | port1 = mb.Port(orientation=vector) 102 | port2 = mb.Port(orientation=-vector) 103 | assert np.allclose(port1["up"].xyz_with_ports, port2["down"].xyz_with_ports) 104 | assert np.allclose(port1["down"].xyz_with_ports, port2["up"].xyz_with_ports) 105 | 106 | def test_port_access_labels(self, ethane): 107 | ethane.remove(ethane[2]) 108 | assert len(ethane["methyl1"]["port[1]"].access_labels) == 1 109 | 110 | ethane.labels["new_port"] = ethane["methyl1"]["port[1]"] 111 | assert len(ethane["new_port"].access_labels) == 2 112 | assert "['new_port']" in ethane["new_port"].access_labels 113 | -------------------------------------------------------------------------------- /mbuild/tests/test_silica_interface.py: -------------------------------------------------------------------------------- 1 | """ 2 | class TestSilicaInterface(BaseTest): 3 | def test_silica_interface(self): 4 | tile_x = 1 5 | tile_y = 1 6 | thickness = 0.6 7 | 8 | interface = SilicaInterface( 9 | bulk_silica=AmorphousSilicaBulk(), 10 | tile_x=tile_x, 11 | tile_y=tile_y, 12 | thickness=thickness, 13 | ) 14 | 15 | thickness_tolerance = 0.05 16 | z = [atom.pos[2] for atom in interface.particles() if atom.name == "Si"] 17 | assert abs(max(z) - min(z) - thickness) < thickness_tolerance 18 | 19 | density_tolerance = 0.1 20 | area = interface.box.lengths[0] * interface.box.lengths[1] 21 | oh_count = len(list(interface.particles_by_name("O_surface"))) 22 | assert abs((oh_count / area) - 5.0) < density_tolerance 23 | 24 | def test_seed(self): 25 | tile_x = 1 26 | tile_y = 1 27 | thickness = 0.6 28 | seed = 12345 29 | 30 | interface1 = SilicaInterface( 31 | bulk_silica=AmorphousSilicaBulk(), 32 | tile_x=tile_x, 33 | tile_y=tile_y, 34 | thickness=thickness, 35 | seed=seed, 36 | ) 37 | atom_names1 = np.array([atom.name for atom in interface1.particles()]) 38 | 39 | interface2 = mb.recipes.SilicaInterface( 40 | bulk_silica=AmorphousSilicaBulk(), 41 | tile_x=tile_x, 42 | tile_y=tile_y, 43 | thickness=thickness, 44 | seed=seed, 45 | ) 46 | atom_names2 = np.array([atom.name for atom in interface2.particles()]) 47 | 48 | assert np.array_equal(atom_names1, atom_names2) 49 | assert np.array_equal(interface1.xyz, interface2.xyz) 50 | """ 51 | -------------------------------------------------------------------------------- /mbuild/tests/test_silica_surface.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pytest 3 | 4 | import mbuild as mb 5 | from mbuild.lib.surfaces import AmorphousSilicaSurface 6 | from mbuild.tests.base_test import BaseTest 7 | 8 | 9 | class TestAmorphousSilicaSurface(BaseTest): 10 | def test_create_amorphous_silica_surface(self): 11 | surface = AmorphousSilicaSurface() 12 | 13 | assert isinstance(surface, mb.Compound) 14 | assert surface.n_particles == 1800 15 | assert surface.n_bonds == 0 16 | assert np.array_equal(surface.periodicity, (True, True, False)) 17 | assert np.array_equal(surface.box.lengths, [5.4366, 4.7082, 1.0]) 18 | 19 | def test_amorphous_silica_surface_error(self): 20 | with pytest.raises(ValueError): 21 | AmorphousSilicaSurface(surface_roughness=2) 22 | -------------------------------------------------------------------------------- /mbuild/tests/test_tiled_compound.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from mbuild.lib.recipes import TiledCompound 4 | from mbuild.tests.base_test import BaseTest 5 | 6 | 7 | class TestTiledCompound(BaseTest): 8 | def test_2d_replication(self, betacristobalite): 9 | nx = 2 10 | ny = 2 11 | nz = 1 12 | tiled = TiledCompound(betacristobalite, [nx, ny, nz]) 13 | assert tiled.n_particles == 1900 * nx * ny 14 | assert tiled.n_bonds == 2400 * nx * ny 15 | for at in tiled.particles(): 16 | if at.name.startswith("Si"): 17 | assert len(list(tiled.bond_graph.neighbors(at))) <= 4 18 | elif at.name.startswith("O"): 19 | assert len(list(tiled.bond_graph.neighbors(at))) <= 2 20 | 21 | def test_no_replication(self, betacristobalite): 22 | nx = 1 23 | ny = 1 24 | nz = 1 25 | tiled = TiledCompound(betacristobalite, [nx, ny, nz]) 26 | assert tiled.n_particles == 1900 * nx * ny 27 | assert tiled.n_bonds == 2400 * nx * ny 28 | 29 | def test_incorrect_periodicity(self, betacristobalite): 30 | nx = 2 31 | ny = 2 32 | nz = 2 33 | with pytest.raises(ValueError): 34 | TiledCompound(betacristobalite, [nx, ny, nz]) 35 | 36 | def test_negative_periodicity(self, betacristobalite): 37 | nx = -2 38 | ny = 3 39 | nz = 2 40 | with pytest.raises(ValueError): 41 | TiledCompound(betacristobalite, [nx, ny, nz]) 42 | -------------------------------------------------------------------------------- /mbuild/tests/test_vasp.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pytest 3 | 4 | from mbuild.formats.vasp import read_poscar, write_poscar 5 | from mbuild.tests.base_test import BaseTest 6 | 7 | 8 | class TestVasp(BaseTest): 9 | """Unit tests for Vasp POSCAR writer""" 10 | 11 | @pytest.fixture(autouse=True) 12 | def initdir(self, tmpdir): 13 | tmpdir.chdir() 14 | 15 | def test_read_write(self, gilmerite): 16 | write_poscar(gilmerite, "test.poscar") 17 | new_gilmerite = read_poscar("test.poscar") 18 | assert np.allclose(gilmerite.box.lengths, new_gilmerite.box.lengths) 19 | assert np.allclose(gilmerite.box.angles, new_gilmerite.box.angles) 20 | assert np.allclose(gilmerite.xyz, new_gilmerite.xyz) 21 | 22 | def test_read_write_direct(self, gilmerite): 23 | write_poscar(gilmerite, "test.poscar", coord_style="direct") 24 | new_gilmerite = read_poscar("test.poscar") 25 | assert np.allclose(gilmerite.box.lengths, new_gilmerite.box.lengths) 26 | assert np.allclose(gilmerite.box.angles, new_gilmerite.box.angles) 27 | assert np.allclose(gilmerite.xyz, new_gilmerite.xyz) 28 | 29 | def test_lattice_constant(self, copper_cell): 30 | write_poscar(copper_cell, "test.poscar", lattice_constant=0.4123) 31 | with open("test.poscar", "r") as f: 32 | for i, line in enumerate(f): 33 | if i == 1: 34 | lattice_constant = np.genfromtxt(line.splitlines(True)) 35 | 36 | assert lattice_constant == 0.4123 37 | 38 | def test_bravais(self, copper_cell): 39 | """Test that compound with no box has a lattice that is diagonal.""" 40 | write_poscar(copper_cell, "test.poscar") 41 | with open("test.poscar", "r") as f: 42 | lines = f.readlines() 43 | 44 | bravais = np.stack([np.fromstring(line, sep=" ") for line in lines[2:5]]) 45 | 46 | # zero the diagonal 47 | for i in range(3): 48 | bravais[i, i] = 0 49 | assert np.array_equal(bravais, np.zeros((3, 3))) 50 | 51 | def test_num_elements(self, cscl_crystal): 52 | write_poscar(cscl_crystal, "test.poscar") 53 | with open("test.poscar", "r") as f: 54 | for i, line in enumerate(f): 55 | if i == 5: 56 | elements = line.split() 57 | 58 | assert len(elements) == 2 59 | 60 | def test_num_atoms(self, copper_cell): 61 | write_poscar(copper_cell, "test.poscar") 62 | with open("test.poscar", "r") as f: 63 | for i, line in enumerate(f): 64 | pass 65 | assert i + 1 == 44 66 | 67 | @pytest.mark.parametrize("coord_type", ["direct", "cartesian"]) 68 | def test_coordinate_header(self, gilmerite, coord_type): 69 | write_poscar(gilmerite, "test.poscar", coord_style=coord_type) 70 | with open("test.poscar", "r") as f: 71 | for i, line in enumerate(f): 72 | if i == 7: 73 | coord = line.strip() 74 | 75 | assert coord == coord_type 76 | 77 | def test_warning_raised(self, copper_cell): 78 | copper_cell.box = None 79 | with pytest.warns(UserWarning): 80 | write_poscar(copper_cell, "test.poscar", coord_style="direct") 81 | 82 | def test_error_raised(self, copper_cell): 83 | with pytest.raises(ValueError): 84 | write_poscar(copper_cell, "test.poscar", coord_style="heck") 85 | -------------------------------------------------------------------------------- /mbuild/utils/__init__.py: -------------------------------------------------------------------------------- 1 | """mBuild utilities.""" 2 | -------------------------------------------------------------------------------- /mbuild/utils/decorators.py: -------------------------------------------------------------------------------- 1 | """Some helpful decorators.""" 2 | 3 | from functools import wraps 4 | from warnings import warn 5 | 6 | 7 | def make_callable(decorator): # pragma: no cover 8 | """Make function callable. 9 | 10 | See https://stackoverflow.com/questions/3888158/making-decorators-with- 11 | optional-arguments 12 | """ 13 | 14 | @wraps(decorator) 15 | def inner(*args, **kw): # pragma: no cover 16 | if len(args) == 1 and not kw and callable(args[0]): 17 | return decorator()(args[0]) 18 | else: 19 | return decorator(*args, **kw) 20 | 21 | return inner 22 | 23 | 24 | def deprecated(warning_string=""): # pragma: no cover 25 | """Decorate deprecated functions.""" 26 | 27 | def old_function(fcn): 28 | def wrapper(*args, **kwargs): 29 | printed_message = f"{fcn.__name__} is deprecated. {warning_string}" 30 | warn(printed_message, DeprecationWarning) 31 | return fcn(*args, **kwargs) 32 | 33 | return wrapper 34 | 35 | return old_function 36 | 37 | 38 | @make_callable 39 | def deprecated_property( 40 | warning_msg="Property deprecated", always=False 41 | ): # pragma: no cover 42 | """Alert users to deprecated properties of an object. 43 | 44 | Deprecation messages are shown only once per runtime by default 45 | 46 | Parameters 47 | ---------- 48 | warning_msg : str, Property deprecated 49 | The deprecation warning to show 50 | always: bool, default=False 51 | If true, always show deprecation warning, default behavior shows 52 | deprecation warning once per runtime 53 | """ 54 | 55 | def old_func(fcn): 56 | class Property(object): 57 | def __init__(self, fget=None, fset=None, fdel=None, doc=None): 58 | self.fget = fget 59 | self.fset = fset 60 | self.fdel = fdel 61 | if doc is None and fget is not None: 62 | doc = fget.__doc__ 63 | self.__doc__ = doc 64 | self.warning_msg = warning_msg 65 | self.always_show = always 66 | 67 | def __get__(self, obj, objtype=None): 68 | self.show_warning_msg() 69 | if obj is None: 70 | return self 71 | if self.fget is None: 72 | raise AttributeError("unreadable attribute") 73 | return self.fget(obj) 74 | 75 | def __set__(self, obj, value): 76 | self.show_warning_msg() 77 | if self.fset is None: 78 | raise AttributeError("can't set attribute") 79 | self.fset(obj, value) 80 | 81 | def __delete__(self, obj): 82 | self.show_warning_msg() 83 | if self.fdel is None: 84 | raise AttributeError("can't delete attribute") 85 | self.fdel(obj) 86 | 87 | def getter(self, fget): 88 | return type(self)(fget, self.fset, self.fdel, self.__doc__) 89 | 90 | def setter(self, fset): 91 | return type(self)(self.fget, fset, self.fdel, self.__doc__) 92 | 93 | def deleter(self, fdel): 94 | return type(self)(self.fget, self.fset, fdel, self.__doc__) 95 | 96 | def show_warning_msg(self): 97 | if self.warning_msg is not None: 98 | warn( 99 | f"Property {fcn.__name__} is deprecated. {self.warning_msg}", 100 | DeprecationWarning, 101 | ) 102 | if not self.always_show: 103 | self.warning_msg = None 104 | 105 | prop = Property(fget=fcn) 106 | return prop 107 | 108 | return old_func 109 | 110 | 111 | def breaking_change(warning_string=""): 112 | """Decorate functions with breaking changes.""" 113 | 114 | def old_function(fcn): 115 | def wrapper(*args, **kwargs): 116 | warn(f"{fcn.__name__} has breaking change. {warning_string}", Warning) 117 | fcn(*args, **kwargs) 118 | 119 | return wrapper 120 | 121 | return old_function 122 | 123 | 124 | def experimental_feature(warning_string=""): # pragma no cover 125 | """Decorate experimental methods.""" 126 | 127 | def experimental_function(fcn): 128 | @wraps(fcn) 129 | def wrapper(*args, **kwargs): 130 | warn( 131 | f"{fcn.__name__} is an experimental feature and is not subject to follow standard deprecation cycles. Use at your own risk! {warning_string}", 132 | Warning, 133 | ) 134 | fcn(*args, **kwargs) 135 | 136 | return wrapper 137 | 138 | return experimental_function 139 | -------------------------------------------------------------------------------- /mbuild/utils/exceptions.py: -------------------------------------------------------------------------------- 1 | """Exceptions for mBuild.""" 2 | 3 | 4 | class RemovedFuncError(Exception): 5 | """Exception for mBuild functions that have been deprecated and removed.""" 6 | 7 | def __init__(self, deprecated_func, new_func, version_deprecated, version_removed): 8 | self.deprecated_func = deprecated_func 9 | self.new_func = new_func 10 | self.version_deprecated = version_deprecated 11 | self.version_removed = version_removed 12 | 13 | def __str__(self): 14 | """Return the string representation of the error.""" 15 | msg = f""" 16 | {self.deprecated_func} has been removed. Please use {self.new_func}. 17 | Deprecated since mBuild version {self.version_deprecated} and removed 18 | in version {self.version_removed}.""" 19 | 20 | return msg 21 | -------------------------------------------------------------------------------- /mbuild/utils/geometry.py: -------------------------------------------------------------------------------- 1 | """mBuild utilites for geometrical operations.""" 2 | 3 | import numpy as np 4 | 5 | import mbuild as mb 6 | from mbuild.coordinate_transform import angle 7 | 8 | 9 | def calc_dihedral(point1, point2, point3, point4): 10 | """Calculate a dihedral angle. 11 | 12 | Here, two planes are defined by (point1, point2, point3) and (point2, 13 | point3, point4). The angle between them is returned. 14 | 15 | Parameters 16 | ---------- 17 | point1, point2, point3, point4 : array-like, shape=(3,), dtype=float 18 | Four points that define two planes 19 | 20 | Returns 21 | ------- 22 | float 23 | The dihedral angle between the two planes defined by the four points. 24 | """ 25 | points = np.array([point1, point2, point3, point4]) 26 | x = np.cross(points[1] - points[0], points[2] - points[1]) 27 | y = np.cross(points[2] - points[1], points[3] - points[2]) 28 | return angle(x, y) 29 | 30 | 31 | def coord_shift(xyz, box): 32 | """Ensure that coordinates are -L/2, L/2. 33 | 34 | Checks if coordinates are -L/2, L/2 and then shifts coordinates if 35 | necessary. For example, if coordinates are 0, L, then a shift is applied to 36 | move coordinates to -L/2, L/2. If a shift is not necessary, the points are 37 | returned unmodified. 38 | 39 | Parameters 40 | ---------- 41 | xyz : numpy.array, shape=(N,3) 42 | Coordinates 43 | box : numpy.array, shape=(N,3) 44 | Array specifing the box lengths, e.g., [Lx, Ly, Lz] 45 | 46 | Returns 47 | ------- 48 | xyz : numpy.array, shape=(N,3) 49 | Shifted coordinates 50 | """ 51 | box = np.asarray(box) 52 | assert box.shape == (3,) 53 | 54 | box_max = box / 2.0 55 | box_min = -box_max 56 | # Shift all atoms 57 | if np.greater(xyz, box_max).any(): 58 | xyz -= box_max 59 | elif np.less(xyz, box_min).any(): 60 | xyz += box_max 61 | 62 | return xyz 63 | 64 | 65 | def wrap_coords(xyz, box, mins=None): 66 | """Wrap coordinates inside box. 67 | 68 | Parameters 69 | ---------- 70 | xyz : numpy.array, shape=(N,3), 71 | Coordinates 72 | box : numpy.array or list or mb.Box 73 | Array or list should have shape (3,) corresponding to box lengths. 74 | If array or list is passed, box is assumed to be positive octant 75 | If mb.box is passed, box can be arbitrarily centered 76 | 77 | Returns 78 | ------- 79 | wrap_xyz : numpy.array, shape=(N,3) 80 | wrapped coordinates 81 | 82 | Notes 83 | ----- 84 | Currently only supports orthorhombic boxes 85 | """ 86 | if not isinstance(box, mb.Box): 87 | box_arr = np.asarray(box) 88 | assert box_arr.shape == (3,) 89 | 90 | wrap_xyz = xyz - 1 * np.floor_divide(xyz, box_arr) * box_arr 91 | else: 92 | xyz = xyz - mins 93 | wrap_xyz = ( 94 | xyz 95 | - (np.floor_divide(xyz, np.asarray(box.lengths)) * np.asarray(box.lengths)) 96 | + mins 97 | ) 98 | 99 | return wrap_xyz 100 | -------------------------------------------------------------------------------- /mbuild/utils/jsutils.py: -------------------------------------------------------------------------------- 1 | """Utilities for communicating with Javascript (js) libraries. 2 | 3 | These are the set of utility methods which are used to communicate with 4 | underlying 'js' libraries by the various notebook visualization libraries used 5 | by mBuild. 6 | """ 7 | 8 | from .io import import_ 9 | 10 | 11 | def overwrite_nglview_default(widget): 12 | """Change the default visualization in nglview. 13 | 14 | This method takes in a nglview.NGLWidget and changes the default hover 15 | behaviour of the widget to add the atom index when it is hovered over the 16 | atom. It also overwrites the click signal from the stage to include extra 17 | information(atom index) in the text display, whenever an atom or bond is 18 | clicked. 19 | 20 | Parameters 21 | ---------- 22 | widget: nglview.NGLWidget, 23 | the ipython widget view. 24 | 25 | Raises 26 | ------ 27 | TypeError: If widget is not of type nglview.NGLWidget 28 | """ 29 | nglview = import_("nglview") 30 | if not isinstance(widget, nglview.NGLWidget): 31 | raise TypeError( 32 | "The argument widget can only be of type nglview.NGLWidget not " 33 | f"{type(widget)}." 34 | ) 35 | tooltip_js = """ 36 | this.stage.mouseControls.add('hoverPick', (stage, pickingProxy) => { 37 | let tooltip = this.stage.tooltip; 38 | if(pickingProxy && pickingProxy.atom && !pickingProxy.bond){ 39 | let atom = pickingProxy.atom; 40 | tooltip.innerText = "ATOM: " + atom.qualifiedName() + ", Index: " + atom.index; 41 | } 42 | }); 43 | """ 44 | 45 | infotext_js = """ 46 | this.stage.signals.clicked.removeAll(); 47 | this.stage.signals.clicked.add((pickingProxy) => { 48 | if(pickingProxy){ 49 | let pickingText = null; 50 | this.model.set('picked', {}); 51 | this.touch(); 52 | let currentPick = {}; 53 | if(pickingProxy.atom){ 54 | currentPick.atom1 = pickingProxy.atom.toObject(); 55 | currentPick.atom1.name = pickingProxy.atom.qualifiedName(); 56 | pickingText = "Atom: " + currentPick.atom1.name + ", Index: " 57 | + pickingProxy.atom.index; 58 | } 59 | else if(pickingProxy.bond){ 60 | currentPick.bond = pickingProxy.bond.toObject(); 61 | currentPick.atom1 = pickingProxy.bond.atom1.toObject(); 62 | currentPick.atom1.name = pickingProxy.bond.atom1.qualifiedName(); 63 | currentPick.atom2 = pickingProxy.bond.atom2.toObject(); 64 | currentPick.atom2.name = pickingProxy.bond.atom2.qualifiedName(); 65 | pickingText = "Bond: " + currentPick.atom1.name + 66 | `(${pickingProxy.bond.atom1.index})` + 67 | " - " + currentPick.atom2.name + 68 | `(${pickingProxy.bond.atom2.index})`; 69 | } 70 | 71 | if(pickingProxy.instance){ 72 | currentPick.instance = pickingProxy.instance; 73 | } 74 | var nComponents = this.stage.compList.length; 75 | for(let i = 0; i < nComponents; i++){ 76 | let comp = this.stage.compList[i]; 77 | if(comp.uuid == pickingProxy.component.uuid){ 78 | currentPick.component = i; 79 | } 80 | } 81 | this.model.set('picked', currentPick); 82 | this.touch(); 83 | this.$pickingInfo.text(pickingText); 84 | } 85 | }); 86 | """ 87 | widget._js(tooltip_js) 88 | widget._js(infotext_js) 89 | -------------------------------------------------------------------------------- /mbuild/utils/orderedset.py: -------------------------------------------------------------------------------- 1 | """Ordered set module.""" 2 | 3 | from collections.abc import MutableSet 4 | 5 | 6 | class OrderedSet(MutableSet): 7 | """An ordered set object with additional convenience methods. 8 | 9 | Taken from code suggested by Vyas in 10 | https://github.com/mosdef-hub/mbuild/issues/865 11 | 12 | Methods 13 | ------- 14 | add 15 | discard 16 | union 17 | intersection 18 | difference 19 | """ 20 | 21 | def __init__(self, *args): 22 | self._data = {value: None for value in args} 23 | 24 | def __repr__(self): 25 | """Return the OrderedSet representation.""" 26 | data = ", ".join(str(i) for i in self._data) 27 | return f"{self.__class__.__name__}({data})" 28 | 29 | def __contains__(self, key): 30 | """Determine whether the element `key` is in the set.""" 31 | return key in self._data 32 | 33 | def __getitem__(self, value): 34 | """Get an item at index `value`.""" 35 | return list(self._data)[value] 36 | 37 | def __iter__(self): 38 | """Iterate through the set.""" 39 | return iter(self._data) 40 | 41 | def __len__(self): 42 | """Return the length.""" 43 | return len(self._data) 44 | 45 | def add(self, value): 46 | """Add a value.""" 47 | self._data[value] = None 48 | 49 | def discard(self, value): 50 | """Remove a value.""" 51 | self._data.pop(value, None) 52 | 53 | def remove(self, value): 54 | """Remove a value. Alias for discard.""" 55 | self.discard(value) 56 | 57 | def union(self, iterable): 58 | """Return the union of this set and an iterable.""" 59 | new = OrderedSet() 60 | new._data = { 61 | **{i: None for i in self._data}, 62 | **{i: None for i in iterable}, 63 | } 64 | return new 65 | 66 | def intersection(self, iterable): 67 | """Return the intersection of this set and an iterable.""" 68 | new = OrderedSet() 69 | new._data = {i: None for i in self._data if i in iterable} 70 | return new 71 | 72 | def difference(self, iterable): 73 | """Return the difference of this set and an iterable.""" 74 | new = OrderedSet() 75 | new._data = {i: None for i in self._data if i not in iterable} 76 | return new 77 | -------------------------------------------------------------------------------- /mbuild/utils/reference/Charmm_writer_testing_only_zeolite.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /mbuild/utils/reference/ETV_triclinic.cif: -------------------------------------------------------------------------------- 1 | data_ETV 2 | 3 | 4 | #************************************************************************** 5 | # 6 | # CIF taken from the IZA-SC Database of Zeolite Structures 7 | # Ch. Baerlocher and L.B. McCusker 8 | # Database of Zeolite Structures: http://www.iza-structure.org/databases/ 9 | # 10 | # The atom coordinates and the cell parameters were optimized with DLS76 11 | # assuming a pure SiO2 composition. 12 | # 13 | #************************************************************************** 14 | 15 | 16 | _cell_length_a 8.7503 17 | _cell_length_b 9.6479 18 | _cell_length_c 10.2719 19 | _cell_angle_alpha 105.7200 20 | _cell_angle_beta 100.1900 21 | _cell_angle_gamma 97.0200 22 | 23 | _symmetry_space_group_name_H-M 'P -1' 24 | _symmetry_Int_Tables_number 2 25 | _symmetry_cell_setting triclinic 26 | 27 | 28 | loop_ 29 | _symmetry_equiv_pos_as_xyz 30 | '+x,+y,+z' 31 | '-x,-y,-z' 32 | 33 | loop_ 34 | _atom_site_label 35 | _atom_site_type_symbol 36 | _atom_site_fract_x 37 | _atom_site_fract_y 38 | _atom_site_fract_z 39 | Si1 Si 0.5462 0.3074 0.1830 40 | Si2 Si 0.5543 0.3985 0.8022 41 | Si3 Si 0.5720 0.0660 0.3233 42 | Si4 Si 0.3062 0.8514 0.3594 43 | Si5 Si 0.3282 0.1836 0.8867 44 | Si6 Si 0.9955 0.7220 0.1426 45 | Si7 Si 0.8127 0.4160 0.0600 46 | O1 O 0.5550 0.2212 0.2975 47 | O2 O 0.6888 0.4517 0.9431 48 | O3 O 0.3997 0.9766 0.3116 49 | O4 O 0.3997 0.3095 0.8273 50 | O5 O 0.4226 0.2094 0.0432 51 | O6 O 0.1229 0.8156 0.2817 52 | O7 O 0.4897 0.4606 0.2413 53 | O8 O 0.7183 0.3390 0.1504 54 | O9 O 0.1446 0.1887 0.8848 55 | O10 O 0.6790 0.0928 0.4756 56 | O11 O 0.6549 0.9739 0.2089 57 | O12 O 0.3816 0.7055 0.3195 58 | O13 O 0.9234 0.5671 0.1585 59 | O14 O 0.9196 0.3078 0.9867 60 | -------------------------------------------------------------------------------- /mbuild/utils/reference/ITG_monoclinic.cif: -------------------------------------------------------------------------------- 1 | data_ITG 2 | 3 | #************************************************************************** 4 | # 5 | # CIF taken from the IZA-SC Database of Zeolite Structures 6 | # Ch. Baerlocher and L.B. McCusker 7 | # Database of Zeolite Structures: http://www.iza-structure.org/databases/ 8 | # 9 | # The atom coordinates and the cell parameters were optimized with DLS76 10 | # assuming a pure SiO2 composition. 11 | # 12 | #************************************************************************** 13 | 14 | _cell_length_a 12.7411(0) 15 | _cell_length_b 12.6989(0) 16 | _cell_length_c 20.9991(0) 17 | _cell_angle_alpha 90.0000(0) 18 | _cell_angle_beta 96.2900(0) 19 | _cell_angle_gamma 90.0000(0) 20 | 21 | _symmetry_space_group_name_H-M 'P 1 2/m 1' 22 | _symmetry_Int_Tables_number 10 23 | _symmetry_cell_setting monoclinic 24 | loop_ 25 | _symmetry_equiv_pos_as_xyz 26 | '+x,+y,+z' 27 | '-x,+y,-z' 28 | '-x,-y,-z' 29 | '+x,-y,+z' 30 | 31 | loop_ 32 | _atom_site_label 33 | _atom_site_type_symbol 34 | _atom_site_fract_x 35 | _atom_site_fract_y 36 | _atom_site_fract_z 37 | T1 Si 0.6467 0.1207 0.2371 38 | T2 Si 0.7955 0.1207 0.3651 39 | T3 Si 0.9866 0.1212 0.2903 40 | T4 Si 0.8387 0.1211 0.1623 41 | T5 Si 0.1183 0.3788 0.0621 42 | T6 Si 0.2697 0.3789 0.1872 43 | T7 Si 0.1459 0.3059 0.2976 44 | T8 Si 0.2866 0.3801 0.4179 45 | T9 Si 0.5118 0.3799 0.3812 46 | T10 Si 0.7332 0.3079 0.4439 47 | T11 Si 0.4953 0.3082 0.2398 48 | T12 Si 0.8956 0.3071 0.0784 49 | T13 Si 0.7900 0.5000 0.3646 50 | T14 Si 0.9914 0.5000 0.2849 51 | T15 Si 0.8474 0.5000 0.1620 52 | T16 Si 0.6459 0.5000 0.2416 53 | O1 O 0.0219 0.3200 0.0908 54 | O2 O 0.0875 0.5000 0.0473 55 | O3 O 0.2225 0.3738 0.1129 56 | O4 O 0.2801 0.5000 0.2097 57 | O5 O 0.3841 0.3237 0.1964 58 | O6 O 0.1911 0.3175 0.2293 59 | O7 O 0.0916 0.1921 0.3025 60 | O8 O 0.0598 0.3964 0.3051 61 | O9 O 0.2413 0.3173 0.3541 62 | O10 O 0.2474 0.3236 0.4797 63 | O11 O 0.2453 0.5000 0.4137 64 | O12 O 0.4137 0.3794 0.4235 65 | O13 O 0.4786 0.3203 0.3144 66 | O14 O 0.5442 0.5000 0.3682 67 | O15 O 0.6092 0.3187 0.4201 68 | O16 O 0.7743 0.1933 0.4253 69 | O17 O 0.7971 0.3966 0.4092 70 | O18 O 0.6811 0.5000 0.3177 71 | O19 O 0.8873 0.5000 0.3219 72 | O20 O 0.9564 0.5000 0.2089 73 | O21 O 0.8402 0.3965 0.1176 74 | O22 O 0.7501 0.5000 0.2047 75 | O23 O 0.5772 0.3966 0.2213 76 | O24 O 0.5429 0.1938 0.2266 77 | O25 O 0.6145 0.0000 0.2217 78 | O26 O 0.7321 0.1579 0.1905 79 | O27 O 0.6969 0.1302 0.3106 80 | O28 O 0.8092 0.0000 0.3879 81 | O29 O 0.9014 0.1594 0.3367 82 | O30 O 0.9373 0.1324 0.2168 83 | O31 O 0.8272 0.0000 0.1399 84 | O32 O 0.8601 0.1931 0.1019 85 | O33 O 0.8583 0.3209 0.0031 86 | O34 O 0.0168 0.0000 0.3055 87 | -------------------------------------------------------------------------------- /mbuild/utils/reference/LaCl3.cif: -------------------------------------------------------------------------------- 1 | # generated using pymatgen 2 | data_LaCl3 3 | _symmetry_space_group_name_H-M 'P 1' 4 | _cell_length_a 7.60296570 5 | _cell_length_b 7.60296570 6 | _cell_length_c 4.37540800 7 | _cell_angle_alpha 90.00000000 8 | _cell_angle_beta 90.00000000 9 | _cell_angle_gamma 120.00000000 10 | _symmetry_Int_Tables_number 1 11 | _chemical_formula_structural LaCl3 12 | _chemical_formula_sum 'La2 Cl6' 13 | _cell_volume 219.03587414 14 | _cell_formula_units_Z 2 15 | loop_ 16 | _symmetry_equiv_pos_site_id 17 | _symmetry_equiv_pos_as_xyz 18 | 1 'x, y, z' 19 | loop_ 20 | _atom_site_type_symbol 21 | _atom_site_label 22 | _atom_site_symmetry_multiplicity 23 | _atom_site_fract_x 24 | _atom_site_fract_y 25 | _atom_site_fract_z 26 | _atom_site_occupancy 27 | La La0 1 0.33333333 0.66666667 0.25000000 1 28 | La La1 1 0.66666667 0.33333333 0.75000000 1 29 | Cl Cl2 1 0.69490400 0.08690400 0.25000000 1 30 | Cl Cl3 1 0.60800000 0.69490400 0.75000000 1 31 | Cl Cl4 1 0.30509600 0.91309600 0.75000000 1 32 | Cl Cl5 1 0.39200000 0.30509600 0.25000000 1 33 | Cl Cl6 1 0.91309600 0.60800000 0.25000000 1 34 | Cl Cl7 1 0.08690400 0.39200000 0.75000000 1 35 | -------------------------------------------------------------------------------- /mbuild/utils/reference/ReS2.cif: -------------------------------------------------------------------------------- 1 | # generated using pymatgen 2 | data_ReS2 3 | _symmetry_space_group_name_H-M 'P 1' 4 | _cell_length_a 6.41910000 5 | _cell_length_b 6.52305930 6 | _cell_length_c 7.04466251 7 | _cell_angle_alpha 91.77954616 8 | _cell_angle_beta 103.97424201 9 | _cell_angle_gamma 118.83663410 10 | _symmetry_Int_Tables_number 1 11 | _chemical_formula_structural ReS2 12 | _chemical_formula_sum 'Re4 S8' 13 | _cell_volume 246.94557322 14 | _cell_formula_units_Z 4 15 | loop_ 16 | _symmetry_equiv_pos_site_id 17 | _symmetry_equiv_pos_as_xyz 18 | 1 'x, y, z' 19 | loop_ 20 | _atom_site_type_symbol 21 | _atom_site_label 22 | _atom_site_symmetry_multiplicity 23 | _atom_site_fract_x 24 | _atom_site_fract_y 25 | _atom_site_fract_z 26 | _atom_site_occupancy 27 | Re Re0 1 0.94176500 0.68947700 0.50807400 1 28 | Re Re1 1 0.05823500 0.31052300 0.49192600 1 29 | Re Re2 1 0.51250400 0.71441700 0.50209100 1 30 | Re Re3 1 0.48749600 0.28558300 0.49790900 1 31 | S S4 1 0.74798600 0.13254800 0.67588400 1 32 | S S5 1 0.73127300 0.34781000 0.26679600 1 33 | S S6 1 0.21989400 0.10784400 0.70096800 1 34 | S S7 1 0.25920200 0.38690600 0.24012300 1 35 | S S8 1 0.74079800 0.61309400 0.75987700 1 36 | S S9 1 0.78010600 0.89215600 0.29903200 1 37 | S S10 1 0.25201400 0.86745200 0.32411600 1 38 | S S11 1 0.26872700 0.65219000 0.73320400 1 39 | -------------------------------------------------------------------------------- /mbuild/utils/reference/benzene-nonatom-nonelement.mol2: -------------------------------------------------------------------------------- 1 | @MOLECULE 2 | ***** 3 | 12 12 0 0 0 4 | SMALL 5 | GASTEIGER 6 | 7 | @ATOM 8 | 1 L -0.1172 2.3334 -0.0000 L 1 UNL1 -0.0618 9 | 2 C -1.3248 1.6367 -0.0000 C.ar 1 UNL1 -0.0618 10 | 3 C -1.3252 0.2425 -0.0000 C.ar 1 UNL1 -0.0618 11 | 4 C -0.1180 -0.4549 -0.0000 C.ar 1 UNL1 -0.0618 12 | 5 C 1.0896 0.2418 -0.0000 C.ar 1 UNL1 -0.0618 13 | 6 C 1.0900 1.6360 -0.0000 C.ar 1 UNL1 -0.0618 14 | 7 H -0.1169 3.4207 -0.0000 H 1 UNL1 0.0618 15 | 8 H -2.2663 2.1806 -0.0000 H 1 UNL1 0.0618 16 | 9 H -2.2670 -0.3009 -0.0000 H 1 UNL1 0.0618 17 | 10 H -0.1183 -1.5422 -0.0000 H 1 UNL1 0.0618 18 | 11 H 2.0310 -0.3021 -0.0000 H 1 UNL1 0.0618 19 | 12 H 2.0318 2.1793 -0.0000 H 1 UNL1 0.0618 20 | @BOND 21 | 1 1 2 ar 22 | 2 2 3 ar 23 | 3 3 4 ar 24 | 4 4 5 ar 25 | 5 5 6 ar 26 | 6 1 6 ar 27 | 7 1 7 1 28 | 8 2 8 1 29 | 9 3 9 1 30 | 10 4 10 1 31 | 11 5 11 1 32 | 12 6 12 1 33 | -------------------------------------------------------------------------------- /mbuild/utils/reference/benzene-nonelement.mol2: -------------------------------------------------------------------------------- 1 | @MOLECULE 2 | ***** 3 | 12 12 0 0 0 4 | SMALL 5 | GASTEIGER 6 | 7 | @ATOM 8 | 1 C -0.1172 2.3334 -0.0000 L 1 UNL1 -0.0618 9 | 2 C -1.3248 1.6367 -0.0000 C.ar 1 UNL1 -0.0618 10 | 3 C -1.3252 0.2425 -0.0000 C.ar 1 UNL1 -0.0618 11 | 4 C -0.1180 -0.4549 -0.0000 C.ar 1 UNL1 -0.0618 12 | 5 C 1.0896 0.2418 -0.0000 C.ar 1 UNL1 -0.0618 13 | 6 C 1.0900 1.6360 -0.0000 C.ar 1 UNL1 -0.0618 14 | 7 H -0.1169 3.4207 -0.0000 H 1 UNL1 0.0618 15 | 8 H -2.2663 2.1806 -0.0000 H 1 UNL1 0.0618 16 | 9 H -2.2670 -0.3009 -0.0000 H 1 UNL1 0.0618 17 | 10 H -0.1183 -1.5422 -0.0000 H 1 UNL1 0.0618 18 | 11 H 2.0310 -0.3021 -0.0000 H 1 UNL1 0.0618 19 | 12 H 2.0318 2.1793 -0.0000 H 1 UNL1 0.0618 20 | @BOND 21 | 1 1 2 ar 22 | 2 2 3 ar 23 | 3 3 4 ar 24 | 4 4 5 ar 25 | 5 5 6 ar 26 | 6 1 6 ar 27 | 7 1 7 1 28 | 8 2 8 1 29 | 9 3 9 1 30 | 10 4 10 1 31 | 11 5 11 1 32 | 12 6 12 1 33 | -------------------------------------------------------------------------------- /mbuild/utils/reference/benzene.mol2: -------------------------------------------------------------------------------- 1 | @MOLECULE 2 | ***** 3 | 12 12 0 0 0 4 | SMALL 5 | GASTEIGER 6 | 7 | @ATOM 8 | 1 C -0.1172 2.3334 -0.0000 C.ar 1 UNL1 -0.0618 9 | 2 C -1.3248 1.6367 -0.0000 C.ar 1 UNL1 -0.0618 10 | 3 C -1.3252 0.2425 -0.0000 C.ar 1 UNL1 -0.0618 11 | 4 C -0.1180 -0.4549 -0.0000 C.ar 1 UNL1 -0.0618 12 | 5 C 1.0896 0.2418 -0.0000 C.ar 1 UNL1 -0.0618 13 | 6 C 1.0900 1.6360 -0.0000 C.ar 1 UNL1 -0.0618 14 | 7 H -0.1169 3.4207 -0.0000 H 1 UNL1 0.0618 15 | 8 H -2.2663 2.1806 -0.0000 H 1 UNL1 0.0618 16 | 9 H -2.2670 -0.3009 -0.0000 H 1 UNL1 0.0618 17 | 10 H -0.1183 -1.5422 -0.0000 H 1 UNL1 0.0618 18 | 11 H 2.0310 -0.3021 -0.0000 H 1 UNL1 0.0618 19 | 12 H 2.0318 2.1793 -0.0000 H 1 UNL1 0.0618 20 | @BOND 21 | 1 1 2 ar 22 | 2 2 3 ar 23 | 3 3 4 ar 24 | 4 4 5 ar 25 | 5 5 6 ar 26 | 6 1 6 ar 27 | 7 1 7 1 28 | 8 2 8 1 29 | 9 3 9 1 30 | 10 4 10 1 31 | 11 5 11 1 32 | 12 6 12 1 33 | -------------------------------------------------------------------------------- /mbuild/utils/reference/cg-chol.pdb: -------------------------------------------------------------------------------- 1 | COMPND UNNAMED 2 | AUTHOR GENERATED BY OPEN BABEL 3 | HETATM 1 XX LIG 1 -3.176 -3.120 -6.537 1.00 0.00 Xx 4 | HETATM 2 XX LIG 1 -3.869 -3.204 -6.323 1.00 0.00 Xx 5 | HETATM 3 XX LIG 1 -3.424 -2.792 -6.387 1.00 0.00 Xx 6 | HETATM 4 XX LIG 1 -4.041 -2.669 -6.107 1.00 0.00 Xx 7 | HETATM 5 XX LIG 1 -4.418 -2.968 -5.867 1.00 0.00 Xx 8 | HETATM 6 XX LIG 1 -4.763 -2.462 -5.649 1.00 0.00 Xx 9 | HETATM 7 XX LIG 1 -5.318 -2.558 -5.289 1.00 0.00 Xx 10 | HETATM 8 XX LIG 1 -3.727 -2.860 -6.625 1.00 0.00 Xx 11 | HETATM 9 XX LIG 1 -4.495 -2.700 -6.205 1.00 0.00 Xx 12 | CONECT 1 2 3 13 | CONECT 2 1 3 4 5 14 | CONECT 2 15 | CONECT 3 1 2 4 8 16 | CONECT 3 17 | CONECT 4 2 3 5 9 18 | CONECT 4 19 | CONECT 5 2 4 6 20 | CONECT 6 5 7 21 | CONECT 7 6 22 | CONECT 8 3 23 | CONECT 9 4 24 | MASTER 0 0 0 0 0 0 0 0 9 0 9 0 25 | END 26 | -------------------------------------------------------------------------------- /mbuild/utils/reference/ch.mol2: -------------------------------------------------------------------------------- 1 | @MOLECULE 2 | ***** 3 | 2 1 0 0 0 4 | SMALL 5 | GASTEIGER 6 | 7 | @ATOM 8 | 1 C 0.1294 0.1294 -0.0000 C.3 1 UNL1 -0.0309 9 | 2 H 0.0989 1.3167 -0.0000 H 1 UNL1 0.0309 10 | @BOND 11 | 1 1 2 1 12 | -------------------------------------------------------------------------------- /mbuild/utils/reference/charmm36_cooh.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /mbuild/utils/reference/charmm_dihedral.mol2: -------------------------------------------------------------------------------- 1 | @MOLECULE 2 | DPPC 3 | 4 3 1 0 1 4 | SMALL 5 | USER_CHARGES 6 | @CRYSIN 7 | 13.9528 17.1622 31.1323 90.0000 90.0000 90.0000 1 1 8 | @ATOM 9 | 1 CTL1 -0.1558 6.4170 4.4541 CTL1 1 DPPC 1.500000 10 | 2 OSL -0.7278 7.6038 3.8783 OSL 1 DPPC -0.780000 11 | 3 PL -0.5108 6.0856 5.8561 PL 1 DPPC -0.780000 12 | 4 OSLP -0.2550 5.1063 3.5611 OSLP 1 DPPC -0.570000 13 | 14 | @BOND 15 | 1 1 2 1 16 | 2 2 3 1 17 | 3 1 4 1 18 | -------------------------------------------------------------------------------- /mbuild/utils/reference/charmm_truncated.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /mbuild/utils/reference/charmm_truncated_singleterm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /mbuild/utils/reference/decane.xyz: -------------------------------------------------------------------------------- 1 | 32 2 | Created with MDTraj 1.9.3, 2019-12-04 3 | C -0.000 -11.200 -0.000 4 | H -1.100 -11.200 -0.000 5 | H 1.100 -11.200 0.000 6 | C -0.000 -9.800 -0.000 7 | H -1.100 -9.800 -0.000 8 | H 1.100 -9.800 -0.000 9 | C -0.000 -8.400 -0.000 10 | H -1.100 -8.400 -0.000 11 | H 1.100 -8.400 -0.000 12 | C -0.000 -7.000 -0.000 13 | H -1.100 -7.000 -0.000 14 | H 1.100 -7.000 -0.000 15 | C -0.000 -5.600 -0.000 16 | H -1.100 -5.600 0.000 17 | H 1.100 -5.600 -0.000 18 | C -0.000 -4.200 0.000 19 | H -1.100 -4.200 0.000 20 | H 1.100 -4.200 -0.000 21 | C -0.000 -2.800 0.000 22 | H -1.100 -2.800 0.000 23 | H 1.100 -2.800 -0.000 24 | C -0.000 -1.400 -0.000 25 | H -1.100 -1.400 0.000 26 | H 1.100 -1.400 -0.000 27 | C 0.000 0.000 0.000 28 | H 1.070 0.000 0.000 29 | H -0.357 0.769 0.653 30 | H -0.357 0.181 -0.993 31 | C -0.000 -12.600 -0.000 32 | H -1.070 -12.600 -0.000 33 | H 0.357 -13.369 0.653 34 | H 0.357 -12.781 -0.993 35 | -------------------------------------------------------------------------------- /mbuild/utils/reference/ecer2.pdb: -------------------------------------------------------------------------------- 1 | COMPND UNNAMED 2 | AUTHOR GENERATED BY OPEN BABEL 3 | HETATM 1 XX LIG 1 -0.856 -3.110 -0.716 1.00 0.00 Xx 4 | HETATM 2 XX LIG 1 -0.907 -3.156 -0.193 1.00 0.00 Xx 5 | HETATM 3 XX LIG 1 -0.876 -3.179 0.370 1.00 0.00 Xx 6 | HETATM 4 XX LIG 1 -0.894 -3.146 0.941 1.00 0.00 Xx 7 | HETATM 5 XX LIG 1 -0.908 -3.272 1.527 1.00 0.00 Xx 8 | HETATM 6 XX LIG 1 -0.828 -3.545 2.131 1.00 0.00 Xx 9 | HETATM 7 XX LIG 1 -0.494 -4.017 2.180 1.00 0.00 Xx 10 | HETATM 8 XX LIG 1 -0.169 -3.643 2.063 1.00 0.00 Xx 11 | HETATM 9 XX LIG 1 -0.027 -3.555 1.466 1.00 0.00 Xx 12 | HETATM 10 XX LIG 1 -0.126 -3.602 0.929 1.00 0.00 Xx 13 | HETATM 11 XX LIG 1 0.028 -3.644 0.310 1.00 0.00 Xx 14 | HETATM 12 XX LIG 1 0.009 -3.548 -0.253 1.00 0.00 Xx 15 | HETATM 13 XX LIG 1 -0.121 -3.509 -0.732 1.00 0.00 Xx 16 | CONECT 1 2 17 | CONECT 2 1 3 18 | CONECT 3 2 4 19 | CONECT 4 3 5 20 | CONECT 5 4 6 21 | CONECT 6 5 7 22 | CONECT 7 6 8 23 | CONECT 8 7 9 24 | CONECT 9 8 10 25 | CONECT 10 9 11 26 | CONECT 11 10 12 27 | CONECT 12 11 13 28 | CONECT 13 12 29 | MASTER 0 0 0 0 0 0 0 0 13 0 13 0 30 | END 31 | -------------------------------------------------------------------------------- /mbuild/utils/reference/ethane.xyz: -------------------------------------------------------------------------------- 1 | 8 2 | Created with MDTraj 1.9.3, 2019-07-22 3 | C 0.000 -1.400 -0.000 4 | H -1.070 -1.400 -0.000 5 | H 0.357 -2.169 0.653 6 | H 0.357 -1.581 -0.993 7 | C 0.000 0.000 0.000 8 | H 1.070 0.000 0.000 9 | H -0.357 0.769 0.653 10 | H -0.357 0.181 -0.993 11 | -------------------------------------------------------------------------------- /mbuild/utils/reference/extra_blank_field.cif: -------------------------------------------------------------------------------- 1 | data_global 2 | _chemical_name_mineral 'Titanite' 3 | loop_ 4 | _publ_author_name 5 | 'Speer J A' 6 | 'Gibbs G V' 7 | _journal_name_full 'American Mineralogist' 8 | _journal_volume 61 9 | _journal_year 1976 10 | _journal_page_first 238 11 | _journal_page_last 247 12 | _publ_section_title 13 | ; 14 | The crystal structure of synthetic titanite, CaTiOSiO4, and the domain textures 15 | of natural titanites 16 | ; 17 | _database_code_amcsd 0000500 18 | _chemical_formula_sum 'Ca Ti Si O5' 19 | _chemical_formula_sum '' 20 | _cell_length_a 7.069 21 | _cell_length_b 8.722 22 | _cell_length_c 6.566 23 | _cell_angle_alpha 90 24 | _cell_angle_beta 113.86 25 | _cell_angle_gamma 90 26 | _cell_volume 370.234 27 | _exptl_crystal_density_diffrn 3.517 28 | _symmetry_space_group_name_H-M 'P 1 21/a 1' 29 | loop_ 30 | _space_group_symop_operation_xyz 31 | 'x,y,z' 32 | '1/2+x,1/2-y,z' 33 | '1/2-x,1/2+y,-z' 34 | '-x,-y,-z' 35 | loop_ 36 | _atom_site_label 37 | _atom_site_fract_x 38 | _atom_site_fract_y 39 | _atom_site_fract_z 40 | Ca 0.24240 0.91840 0.75120 41 | Ti 0.51340 0.75420 0.24950 42 | Si 0.74860 0.93300 0.74900 43 | O1 0.74990 0.82020 0.25020 44 | O2 0.91080 0.81620 0.93470 45 | O3 0.38270 0.96080 0.14590 46 | O4 0.91220 0.31650 0.43680 47 | O5 0.38130 0.46010 0.64680 48 | loop_ 49 | _atom_site_aniso_label 50 | _atom_site_aniso_U_11 51 | _atom_site_aniso_U_22 52 | _atom_site_aniso_U_33 53 | _atom_site_aniso_U_12 54 | _atom_site_aniso_U_13 55 | _atom_site_aniso_U_23 56 | Ca 0.02200 0.00497 0.00537 0.00069 -0.00098 0.00029 57 | Ti 0.00737 0.00451 0.00327 0.00031 0.00126 0.00027 58 | Si 0.00474 0.00258 0.00192 -0.00029 0.00092 0.00003 59 | O1 0.00874 0.00736 0.01253 0.00109 0.00680 0.00122 60 | O2 0.01196 0.00856 0.00495 0.00071 0.00035 0.00019 61 | O3 0.00938 0.01064 0.00510 0.00120 0.00210 0.00125 62 | O4 0.01211 0.00863 0.00356 0.00157 0.00112 0.00103 63 | O5 0.00828 0.00663 0.00590 0.00166 0.00153 0.00175 64 | -------------------------------------------------------------------------------- /mbuild/utils/reference/gaff_test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /mbuild/utils/reference/lj.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /mbuild/utils/reference/methane_oplssaa.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /mbuild/utils/reference/methyl.mol2: -------------------------------------------------------------------------------- 1 | @MOLECULE 2 | ***** 3 | 4 3 0 0 0 4 | SMALL 5 | GASTEIGER 6 | 7 | @ATOM 8 | 1 C1 -1.7501 1.6619 0.0000 C.3 1 LIG1 -0.0681 9 | 2 H1 -0.6801 1.6619 0.0000 H 1 LIG1 0.0227 10 | 3 H2 -2.1067 2.4310 0.6528 H 1 LIG1 0.0227 11 | 4 H3 -2.1067 1.8427 -0.9925 H 1 LIG1 0.0227 12 | @BOND 13 | 1 1 2 1 14 | 2 1 3 1 15 | 3 1 4 1 16 | -------------------------------------------------------------------------------- /mbuild/utils/reference/methyl.pdb: -------------------------------------------------------------------------------- 1 | COMPND UNNAMED 2 | AUTHOR GENERATED BY OPEN BABEL 3 | ATOM 1 C LIG A 1 -1.750 1.662 0.000 1.00 0.00 C 4 | ATOM 2 H LIG A 1 -0.680 1.662 0.000 1.00 0.00 H 5 | ATOM 3 H LIG A 1 -2.107 2.431 0.653 1.00 0.00 H 6 | ATOM 4 H LIG A 1 -2.107 1.843 -0.993 1.00 0.00 H 7 | CONECT 1 2 3 4 8 | CONECT 2 1 9 | CONECT 3 1 10 | CONECT 4 1 11 | MASTER 0 0 0 0 0 0 0 0 4 0 4 0 12 | END 13 | -------------------------------------------------------------------------------- /mbuild/utils/reference/needs_to_be_wrapped.cif: -------------------------------------------------------------------------------- 1 | #********************************************************************************* 2 | # 3 | # Crystallographic Information File for Tetrapropylammonium_ZSM-5 4 | # 5 | # Reference : 6 | # van Koningsveld, H., van Bekkum, H. and Jansen, J.C. 7 | # Acta Crystallogr., B43, 127-132, (1987) 8 | # 9 | # 10 | # CIF downloaded from the IZA-SC Database of Zeolite Structures 11 | # Ch. Baerlocher and L.B. McCusker, 12 | # Database of Zeolite Structures: http://www.iza-structure.org/databases/ 13 | # 14 | #********************************************************************************** 15 | 16 | 17 | data_Tetrapropylammonium_ZSM-5 18 | _chemical_name_systematic 19 | '*ZSM-5' 20 | _chemical_formula_structural 21 | '|(C12N)4| [Si96O192]' 22 | _cell_length_a 20.022 23 | _cell_length_b 19.899 24 | _cell_length_c 13.383 25 | _cell_angle_alpha 90 26 | _cell_angle_beta 90 27 | _cell_angle_gamma 90 28 | _cell_formula_units_Z 1 29 | 30 | _space_group.name_H-M_ref 'P n m a' 31 | _symmetry_space_group_name_H-M 'P n m a' 32 | _symmetry_space_group_name_Hall '-P 2ac 2n' 33 | _space_group.IT_number 62 34 | 35 | 36 | loop_ 37 | _atom_site_label 38 | _atom_site_type_symbol 39 | _atom_site_fract_x 40 | _atom_site_fract_y 41 | _atom_site_fract_z 42 | _atom_site_B_iso_or_equiv 43 | _atom_site_occupancy 44 | SI1 Si 0.42238 0.0565 -0.33598 1.39 1 45 | SI2 Si 0.30716 0.02772 -0.1893 1.63 1 46 | SI3 Si 0.27911 0.06127 0.0312 1.52 1 47 | SI4 Si 0.12215 0.06298 0.0267 1.43 1 48 | SI5 Si 0.07128 0.02722 -0.18551 1.26 1 49 | SI6 Si 0.18641 0.05896 -0.32818 1.41 1 50 | SI7 Si 0.42265 -0.1725 -0.32718 1.46 1 51 | SI8 Si 0.30778 -0.13016 -0.18548 1.57 1 52 | SI9 Si 0.27554 -0.17279 0.03109 1.39 1 53 | SI10 Si 0.12058 -0.1731 0.02979 1.52 1 54 | SI11 Si 0.07044 -0.13037 -0.182 1.52 1 55 | SI12 Si 0.18706 -0.17327 -0.31933 1.58 1 56 | O1 O 0.3726 0.0534 -0.2442 3.87 1 57 | O2 O 0.3084 0.0587 -0.0789 3.16 1 58 | O3 O 0.2007 0.0592 0.0289 5.05 1 59 | O4 O 0.0969 0.0611 -0.0856 3.47 1 60 | O5 O 0.1149 0.0541 -0.2763 2.68 1 61 | O6 O 0.2435 0.0553 -0.246 3.63 1 62 | O7 O 0.3742 -0.1561 -0.2372 3.71 1 63 | O8 O 0.3085 -0.1552 -0.0728 3.47 1 64 | O9 O 0.198 -0.1554 0.0288 3.16 1 65 | O10 O 0.091 -0.1614 -0.0777 4.58 1 66 | O11 O 0.1169 -0.1578 -0.2694 3.79 1 67 | O12 O 0.2448 -0.1594 -0.2422 4.34 1 68 | O13 O 0.3047 -0.051 -0.1866 5.61 1 69 | O14 O 0.0768 -0.0519 -0.1769 3.71 1 70 | O15 O 0.4161 0.1276 -0.3896 3.47 1 71 | O16 O 0.4086 -0.0017 -0.4136 3.63 1 72 | O17 O 0.402 -0.1314 -0.4239 3.16 1 73 | O18 O 0.1886 0.1298 -0.3836 2.84 1 74 | O19 O 0.194 0.0007 -0.4082 3.55 1 75 | O20 O 0.1951 -0.1291 -0.419 3.4 1 76 | O21 O -0.0037 0.0502 -0.208 2.61 1 77 | O22 O -0.004 -0.1528 -0.2078 3.16 1 78 | O23 O 0.4192 -0.25 -0.354 3.47 1 79 | O24 O 0.1884 -0.25 -0.3538 2.68 1 80 | O25 O 0.2883 -0.25 0.0579 2.61 1 81 | O26 O 0.1085 -0.25 0.0611 2.37 1 82 | N N 0.4762 0.25 -0.1095 5.45 1 83 | C1 C 0.495 0.233 -0.221 4.58 0.3 84 | C2 C 0.568 0.25 -0.241 7.66 0.6 85 | C3 C 0.578 0.25 -0.362 7.74 0.6 86 | C4 C 0.399 0.274 -0.1 5.05 0.3 87 | C5 C 0.355 0.228 -0.15 10.74 0.3 88 | C6 C 0.278 0.25 -0.147 8.21 0.6 89 | C7 C 0.505 0.319 -0.089 5.13 0.3 90 | C8 C 0.473 0.334 -0.019 6.55 0.3 91 | C9 C 0.496 0.412 0.045 6.95 0.5 92 | C10 C 0.508 0.199 -0.032 9.55 0.5 93 | C11 C 0.49 0.124 -0.045 8.61 0.5 94 | C12 C 0.529 0.088 0.033 5.68 0.5 95 | C21 C 0.413 0.229 -0.166 6.55 0.2 96 | C22 C 0.355 0.272 -0.15 10.74 0.2 97 | C23 C 0.285 0.25 -0.195 8.69 0.4 98 | C24 C 0.534 0.279 -0.185 5.29 0.2 99 | C25 C 0.546 0.225 -0.263 5.76 0.2 100 | C26 C 0.601 0.25 -0.332 10.19 0.4 101 | C27 C 0.468 0.315 -0.06 4.82 0.2 102 | C28 C 0.516 0.335 0.02 4.82 0.2 103 | 104 | # End of data for Tetrapropylammonium_ZSM-5 105 | -------------------------------------------------------------------------------- /mbuild/utils/reference/p3ht.smi: -------------------------------------------------------------------------------- 1 | CCCCCCC1=C(SC(=C1)C)C 2 | -------------------------------------------------------------------------------- /mbuild/utils/reference/pro_but.pdb: -------------------------------------------------------------------------------- 1 | CRYST1 7.200 10.738 6.646 90.00 90.00 90.00 P 1 2 | ATOM 1 C pro 1 -0.000 -1.400 -0.000 0.00 0.00 C 3 | ATOM 2 H pro 1 -1.100 -1.400 0.000 0.00 0.00 H 4 | ATOM 3 H pro 1 1.100 -1.400 -0.000 0.00 0.00 H 5 | ATOM 4 C pro 1 0.000 0.000 0.000 0.00 0.00 C 6 | ATOM 5 H pro 1 1.070 0.000 0.000 0.00 0.00 H 7 | ATOM 6 H pro 1 -0.357 0.769 0.653 0.00 0.00 H 8 | ATOM 7 H pro 1 -0.357 0.181 -0.993 0.00 0.00 H 9 | ATOM 8 C pro 1 0.000 -2.800 -0.000 0.00 0.00 C 10 | ATOM 9 H pro 1 -1.070 -2.800 -0.000 0.00 0.00 H 11 | ATOM 10 H pro 1 0.357 -3.569 0.653 0.00 0.00 H 12 | ATOM 11 H pro 1 0.357 -2.981 -0.993 0.00 0.00 H 13 | TER 12 pro 1 14 | HETATM 13 C but 2 0.000 -2.800 -0.000 0.00 0.00 C 15 | HETATM 14 H but 2 -1.100 -2.800 -0.000 0.00 0.00 H 16 | HETATM 15 H but 2 1.100 -2.800 0.000 0.00 0.00 H 17 | HETATM 16 C but 2 0.000 -1.400 -0.000 0.00 0.00 C 18 | HETATM 17 H but 2 -1.100 -1.400 0.000 0.00 0.00 H 19 | HETATM 18 H but 2 1.100 -1.400 -0.000 0.00 0.00 H 20 | HETATM 19 C but 2 0.000 0.000 0.000 0.00 0.00 C 21 | HETATM 20 H but 2 1.070 0.000 0.000 0.00 0.00 H 22 | HETATM 21 H but 2 -0.357 0.769 0.653 0.00 0.00 H 23 | HETATM 22 H but 2 -0.357 0.181 -0.993 0.00 0.00 H 24 | HETATM 23 C but 2 0.000 -4.200 0.000 0.00 0.00 C 25 | HETATM 24 H but 2 -1.070 -4.200 -0.000 0.00 0.00 H 26 | HETATM 25 H but 2 0.357 -4.969 0.653 0.00 0.00 H 27 | HETATM 26 H but 2 0.357 -4.381 -0.993 0.00 0.00 H 28 | END 29 | -------------------------------------------------------------------------------- /mbuild/utils/reference/restart.gsd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mosdef-hub/mbuild/8305c205a838fe1145acdd1450852542ef6926ec/mbuild/utils/reference/restart.gsd -------------------------------------------------------------------------------- /mbuild/utils/reference/small_oplsaa.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /mbuild/utils/reference/spc.pdb: -------------------------------------------------------------------------------- 1 | CRYST1 22.288 22.288 22.288 90.00 90.00 90.00 P 1 1 2 | ATOM 1 _HW SPC S 1 4.828 12.617 12.371 0.00 0.00 SPC 3 | ATOM 2 _OW SPC S 1 4.341 13.484 12.270 0.00 0.00 SPC 4 | ATOM 3 _HW SPC S 1 4.505 14.054 13.077 0.00 0.00 SPC 5 | END 6 | CONECT 1 2 7 | CONECT 2 3 8 | -------------------------------------------------------------------------------- /mbuild/utils/reference/styrene.mol2: -------------------------------------------------------------------------------- 1 | @MOLECULE 2 | ***** 3 | 16 16 0 0 0 4 | SMALL 5 | GASTEIGER 6 | Energy = 0 7 | 8 | @ATOM 9 | 1 C 0.9779 -0.1035 0.1521 C.2 1 LIG1 -0.0981 10 | 2 C 2.2964 -0.0143 -0.0100 C.2 1 LIG1 -0.0617 11 | 3 C 3.0006 1.2797 -0.0423 C.ar 1 LIG1 -0.0256 12 | 4 C 2.3148 2.4926 0.1316 C.ar 1 LIG1 -0.0546 13 | 5 C 3.0090 3.7071 0.0829 C.ar 1 LIG1 -0.0612 14 | 6 C 4.3871 3.7129 -0.1420 C.ar 1 LIG1 -0.0617 15 | 7 C 5.0746 2.5092 -0.3140 C.ar 1 LIG1 -0.0612 16 | 8 C 4.3825 1.2949 -0.2632 C.ar 1 LIG1 -0.0546 17 | 9 H 0.5216 -1.0290 0.1692 H 1 LIG1 0.0535 18 | 10 H 0.4122 0.7528 0.2607 H 1 LIG1 0.0535 19 | 11 H 2.8445 -0.8821 -0.1169 H 1 LIG1 0.0618 20 | 12 H 1.2959 2.4887 0.2957 H 1 LIG1 0.0623 21 | 13 H 2.5030 4.5971 0.2131 H 1 LIG1 0.0618 22 | 14 H 4.8987 4.6083 -0.1812 H 1 LIG1 0.0618 23 | 15 H 6.0934 2.5159 -0.4785 H 1 LIG1 0.0618 24 | 16 H 4.8928 0.4067 -0.3892 H 1 LIG1 0.0623 25 | @BOND 26 | 1 3 4 ar 27 | 2 4 5 ar 28 | 3 3 8 ar 29 | 4 7 8 ar 30 | 5 6 7 ar 31 | 6 5 6 ar 32 | 7 1 2 2 33 | 8 2 3 1 34 | 9 1 9 1 35 | 10 1 10 1 36 | 11 2 11 1 37 | 12 4 12 1 38 | 13 5 13 1 39 | 14 6 14 1 40 | 15 7 15 1 41 | 16 8 16 1 42 | -------------------------------------------------------------------------------- /mbuild/utils/reference/tip3p_water.xyz: -------------------------------------------------------------------------------- 1 | 3 2 | tip3p_water.xyz - created by mBuild 3 | opls_111 0.610000 1.000000 1.000000 4 | opls_112 0.170000 0.900000 1.770000 5 | opls_112 0.110000 1.540000 0.400000 6 | -------------------------------------------------------------------------------- /mbuild/utils/reference/too_few_atoms.xyz: -------------------------------------------------------------------------------- 1 | 10 2 | Created with MDTraj 1.8.0, 2018-05-09 3 | C 0.000 -1.400 -0.000 4 | H -1.070 -1.400 0.000 5 | H 0.357 -2.169 0.653 6 | H 0.357 -1.581 -0.993 7 | C 0.000 0.000 0.000 8 | H 1.070 0.000 0.000 9 | H -0.357 0.769 0.653 10 | H -0.357 0.181 -0.993 11 | -------------------------------------------------------------------------------- /mbuild/utils/reference/too_many_atoms.xyz: -------------------------------------------------------------------------------- 1 | 6 2 | Created with MDTraj 1.8.0, 2018-05-09 3 | C 0.000 -1.400 -0.000 4 | H -1.070 -1.400 0.000 5 | H 0.357 -2.169 0.653 6 | H 0.357 -1.581 -0.993 7 | C 0.000 0.000 0.000 8 | H 1.070 0.000 0.000 9 | H -0.357 0.769 0.653 10 | H -0.357 0.181 -0.993 11 | -------------------------------------------------------------------------------- /mbuild/utils/sorting.py: -------------------------------------------------------------------------------- 1 | """mBuild sorting utilities.""" 2 | 3 | import re 4 | 5 | 6 | def _atoi(text): 7 | return int(text) if text.isdigit() else text 8 | 9 | 10 | def natural_sort(text): 11 | """Break apart a string containing letters and digits.""" 12 | return [_atoi(a) for a in re.split(r"(\d+)", text)] 13 | -------------------------------------------------------------------------------- /mbuild/utils/validation.py: -------------------------------------------------------------------------------- 1 | """Validation module.""" 2 | 3 | 4 | def assert_port_exists(port_name, compound): 5 | """Ensure that a Port label exists in a Compound.""" 6 | if port_name in compound.labels: 7 | return True 8 | else: 9 | from mbuild.port import Port 10 | 11 | available_ports = [ 12 | name for name in compound.labels if isinstance(compound.labels[name], Port) 13 | ] 14 | compound_name = compound.__class__.__name__ 15 | raise ValueError( 16 | "No port named '{port_name}' in {compound_name}'s labels. Labeled " 17 | "Ports in {compound_name} are: {available_ports}".format(**locals()) 18 | ) 19 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=61.2"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [project] 6 | name = "mbuild" 7 | description = "A hierarchical, component based molecule builder." 8 | readme = "README.md" 9 | authors = [ 10 | {name = "Janos Sallai", email = "janos.sallai@vanderbilt.edu"}, 11 | {name = "Christopher Klein", email = "christoph.klein@vanderbilt.edu"}, 12 | ] 13 | maintainers = [ 14 | {name = "Nicholas Craven", email = "nicholas.c.craven@vanderbilt.edu"}, 15 | {name = "Chris Jones", email = "chrisjones4@u.boisestate.edu"}, 16 | ] 17 | license= {text = "MIT"} 18 | classifiers=[ 19 | "Intended Audience :: Science/Research", 20 | "Intended Audience :: Developers", 21 | "License :: OSI Approved :: MIT License", 22 | "Natural Language :: English", 23 | "Programming Language :: Python", 24 | "Programming Language :: Python :: 3", 25 | "Topic :: Scientific/Engineering :: Chemistry", 26 | "Operating System :: Microsoft :: Windows", 27 | "Operating System :: POSIX", 28 | "Operating System :: Unix", 29 | "Operating System :: MacOS", 30 | ] 31 | urls = {Homepage = "https://github.com/mosdef-hub/mbuild"} 32 | requires-python = ">=3.9" 33 | dynamic = ["version"] 34 | 35 | [tool.setuptools] 36 | zip-safe = false 37 | include-package-data = true 38 | license-files = ["LICENSE"] 39 | 40 | [tool.setuptools.packages] 41 | find = {namespaces = false} 42 | 43 | [tool.setuptools.package-data] 44 | mbuild = ['"utils/**"', '"lib/**"'] 45 | 46 | [tool.setuptools.dynamic] 47 | version = {attr = "mbuild.__version__"} 48 | 49 | [project.entry-points."mbuild.plugins"] 50 | Alkane = "mbuild.lib.recipes.alkane:Alkane" 51 | Monolayer = "mbuild.lib.recipes.monolayer:Monolayer" 52 | Polymer = "mbuild.lib.recipes.polymer:Polymer" 53 | SilicaInterface = "mbuild.lib.recipes.silica_interface:SilicaInterface" 54 | TiledCompound = "mbuild.lib.recipes.tiled_compound:TiledCompound" 55 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 1.0.0 3 | commit = True 4 | tag = True 5 | message = Bump to version {new_version} 6 | tag_name = {new_version} 7 | 8 | [coverage:run] 9 | omit = 10 | mbuild/examples/* 11 | mbuild/tests/* 12 | 13 | [coverage:report] 14 | exclude_lines = 15 | pragma: no cover 16 | 17 | if 0: 18 | if __name__ == .__main__.: 19 | def __repr__ 20 | except ImportError 21 | omit = 22 | mbuild/examples/* 23 | mbuild/tests/* 24 | 25 | [bumpversion:file:mbuild/__init__.py] 26 | 27 | [bumpversion:file:docs/conf.py] 28 | --------------------------------------------------------------------------------