mdinterface 1.3.0__tar.gz → 1.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. mdinterface-1.4.0/MANIFEST.in +26 -0
  2. {mdinterface-1.3.0 → mdinterface-1.4.0}/PKG-INFO +118 -39
  3. mdinterface-1.3.0/mdinterface.egg-info/PKG-INFO → mdinterface-1.4.0/README.md +87 -52
  4. mdinterface-1.4.0/assets/mdinterface.png +0 -0
  5. {mdinterface-1.3.0 → mdinterface-1.4.0}/mdinterface/__init__.py +2 -2
  6. {mdinterface-1.3.0 → mdinterface-1.4.0}/mdinterface/build/box.py +142 -15
  7. mdinterface-1.4.0/mdinterface/build/polymerize.py +306 -0
  8. mdinterface-1.4.0/mdinterface/build/snippets.py +140 -0
  9. mdinterface-1.4.0/mdinterface/core/polymer.py +170 -0
  10. {mdinterface-1.3.0 → mdinterface-1.4.0}/mdinterface/core/specie.py +316 -104
  11. {mdinterface-1.3.0 → mdinterface-1.4.0}/mdinterface/core/topology.py +123 -16
  12. {mdinterface-1.3.0 → mdinterface-1.4.0}/mdinterface/database/ions.py +5 -3
  13. mdinterface-1.4.0/mdinterface/examples/make_box.py +76 -0
  14. mdinterface-1.4.0/mdinterface/examples/make_polymer.py +74 -0
  15. mdinterface-1.4.0/mdinterface/examples/make_solvent_box.py +67 -0
  16. mdinterface-1.4.0/mdinterface/examples/make_specie_ligpargen_resp.py +26 -0
  17. {mdinterface-1.3.0 → mdinterface-1.4.0}/mdinterface/externals/__init__.py +8 -0
  18. mdinterface-1.4.0/mdinterface/externals/aimd.py +103 -0
  19. {mdinterface-1.3.0 → mdinterface-1.4.0}/mdinterface/externals/ligpargen.py +27 -9
  20. mdinterface-1.4.0/mdinterface/externals/optimization.py +80 -0
  21. {mdinterface-1.3.0 → mdinterface-1.4.0}/mdinterface/io/lammpswriter.py +142 -0
  22. {mdinterface-1.3.0 → mdinterface-1.4.0}/mdinterface/io/read.py +2 -2
  23. mdinterface-1.4.0/mdinterface/read/cp2ktraj.py +139 -0
  24. mdinterface-1.4.0/mdinterface/read/lammpstraj.py +73 -0
  25. mdinterface-1.4.0/mdinterface/read/read.py +270 -0
  26. mdinterface-1.4.0/mdinterface/read/trajectory.py +402 -0
  27. mdinterface-1.4.0/mdinterface/read/xyztraj.py +33 -0
  28. mdinterface-1.4.0/mdinterface/simulationbox.py +577 -0
  29. {mdinterface-1.3.0 → mdinterface-1.4.0}/mdinterface/utils/graphs.py +1 -1
  30. {mdinterface-1.3.0 → mdinterface-1.4.0}/mdinterface/utils/map.py +6 -3
  31. mdinterface-1.3.0/README.md → mdinterface-1.4.0/mdinterface.egg-info/PKG-INFO +131 -20
  32. {mdinterface-1.3.0 → mdinterface-1.4.0}/mdinterface.egg-info/SOURCES.txt +13 -1
  33. mdinterface-1.4.0/mdinterface.egg-info/requires.txt +19 -0
  34. {mdinterface-1.3.0 → mdinterface-1.4.0}/mdinterface.egg-info/top_level.txt +2 -0
  35. mdinterface-1.4.0/pyproject.toml +65 -0
  36. mdinterface-1.4.0/requirements.txt +7 -0
  37. mdinterface-1.4.0/setup.cfg +4 -0
  38. mdinterface-1.3.0/MANIFEST.in +0 -1
  39. mdinterface-1.3.0/mdinterface/build/polymerize.py +0 -95
  40. mdinterface-1.3.0/mdinterface/core/polymer.py +0 -158
  41. mdinterface-1.3.0/mdinterface/simulationbox.py +0 -447
  42. mdinterface-1.3.0/mdinterface.egg-info/requires.txt +0 -17
  43. mdinterface-1.3.0/pyproject.toml +0 -3
  44. mdinterface-1.3.0/requirements.txt +0 -6
  45. mdinterface-1.3.0/setup.cfg +0 -37
  46. {mdinterface-1.3.0 → mdinterface-1.4.0}/LICENSE +0 -0
  47. {mdinterface-1.3.0 → mdinterface-1.4.0}/mdinterface/build/__init__.py +0 -0
  48. {mdinterface-1.3.0 → mdinterface-1.4.0}/mdinterface/build/charges.py +0 -0
  49. {mdinterface-1.3.0 → mdinterface-1.4.0}/mdinterface/build/continuum2sim.py +0 -0
  50. {mdinterface-1.3.0 → mdinterface-1.4.0}/mdinterface/config.py +0 -0
  51. {mdinterface-1.3.0 → mdinterface-1.4.0}/mdinterface/core/__init__.py +0 -0
  52. {mdinterface-1.3.0 → mdinterface-1.4.0}/mdinterface/database/__init__.py +0 -0
  53. {mdinterface-1.3.0 → mdinterface-1.4.0}/mdinterface/database/graphene.py +0 -0
  54. {mdinterface-1.3.0 → mdinterface-1.4.0}/mdinterface/database/metals.py +0 -0
  55. {mdinterface-1.3.0 → mdinterface-1.4.0}/mdinterface/database/molecules.py +0 -0
  56. {mdinterface-1.3.0 → mdinterface-1.4.0}/mdinterface/externals/obabel.py +0 -0
  57. {mdinterface-1.3.0 → mdinterface-1.4.0}/mdinterface/externals/pyscf.py +0 -0
  58. {mdinterface-1.3.0 → mdinterface-1.4.0}/mdinterface/io/__init__.py +0 -0
  59. {mdinterface-1.3.0 → mdinterface-1.4.0}/mdinterface/io/packmol.py +0 -0
  60. {mdinterface-1.3.0 → mdinterface-1.4.0}/mdinterface/utils/__init__.py +0 -0
  61. {mdinterface-1.3.0 → mdinterface-1.4.0}/mdinterface/utils/auxiliary.py +0 -0
  62. {mdinterface-1.3.0 → mdinterface-1.4.0}/mdinterface/utils/draw.py +0 -0
  63. {mdinterface-1.3.0 → mdinterface-1.4.0}/mdinterface/utils/poisson.py +0 -0
  64. {mdinterface-1.3.0 → mdinterface-1.4.0}/mdinterface/utils/units.py +0 -0
  65. {mdinterface-1.3.0 → mdinterface-1.4.0}/mdinterface.egg-info/dependency_links.txt +0 -0
  66. {mdinterface-1.3.0 → mdinterface-1.4.0}/setup.py +0 -0
@@ -0,0 +1,26 @@
1
+ # Include important files
2
+ include README.md
3
+ include LICENSE
4
+ include requirements.txt
5
+ include pyproject.toml
6
+
7
+ # Include package data
8
+ recursive-include mdinterface *.py
9
+ recursive-include mdinterface/database *.json *.txt *.dat
10
+ recursive-include mdinterface/examples *.py
11
+ recursive-include mdinterface/config *.ini
12
+
13
+ # Include documentation and assets if they exist
14
+ recursive-include docs *
15
+ include assets/*
16
+
17
+ # Exclude unwanted files
18
+ exclude *.pyc
19
+ exclude *~
20
+ exclude *.bak
21
+ exclude .DS_Store
22
+ recursive-exclude * __pycache__
23
+ recursive-exclude * *.py[co]
24
+ recursive-exclude * .git*
25
+ recursive-exclude * .tox*
26
+ recursive-exclude * .pytest_cache*
@@ -1,33 +1,45 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mdinterface
3
- Version: 1.3.0
3
+ Version: 1.4.0
4
4
  Summary: Build Interface Systems for Molecular Dynamics Simulations
5
- Home-page: https://gitlab.com/roncofaber/mdinterface
6
- Author: Fabrice Roncoroni
7
- Author-email: fabrice.roncoroni@gmail.com
8
- License: Apache-2.0
9
- Classifier: Programming Language :: Python :: 3
10
- Classifier: License :: OSI Approved :: Apache Software License
5
+ Author-email: Fabrice Roncoroni <fabrice.roncoroni@gmail.com>
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Homepage, https://gitlab.com/roncofaber/mdinterface
8
+ Project-URL: Repository, https://gitlab.com/roncofaber/mdinterface.git
9
+ Project-URL: Documentation, https://gitlab.com/roncofaber/mdinterface
10
+ Project-URL: Bug Tracker, https://gitlab.com/roncofaber/mdinterface/-/issues
11
+ Keywords: molecular dynamics,simulation,interface,chemistry,materials science
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Science/Research
11
14
  Classifier: Operating System :: OS Independent
12
- Classifier: Topic :: Software Development
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.8
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
13
21
  Classifier: Topic :: Scientific/Engineering
22
+ Classifier: Topic :: Scientific/Engineering :: Chemistry
23
+ Classifier: Topic :: Scientific/Engineering :: Physics
14
24
  Requires-Python: >=3.8
15
25
  Description-Content-Type: text/markdown
16
26
  License-File: LICENSE
17
- Requires-Dist: mdanalysis
18
- Requires-Dist: ase
19
- Requires-Dist: numpy
20
- Requires-Dist: networkx
21
- Requires-Dist: platformdirs
22
- Requires-Dist: configparser
23
- Provides-Extra: volume
24
- Requires-Dist: libarvo; extra == "volume"
27
+ Requires-Dist: mdanalysis>=2.0.0
28
+ Requires-Dist: ase>=3.22.0
29
+ Requires-Dist: numpy>=1.20.0
30
+ Requires-Dist: networkx>=2.5
31
+ Requires-Dist: platformdirs>=2.0.0
32
+ Requires-Dist: configparser>=5.0.0
33
+ Requires-Dist: libarvo
25
34
  Provides-Extra: resp
26
- Requires-Dist: pyscf; extra == "resp"
35
+ Requires-Dist: pyscf>=2.0.0; extra == "resp"
27
36
  Requires-Dist: pymbxas; extra == "resp"
37
+ Provides-Extra: aimd
38
+ Requires-Dist: fairchem-core; extra == "aimd"
28
39
  Provides-Extra: all
29
- Requires-Dist: libarvo; extra == "all"
30
- Requires-Dist: pyscf; extra == "all"
40
+ Requires-Dist: pyscf>=2.0.0; extra == "all"
41
+ Requires-Dist: pymbxas; extra == "all"
42
+ Requires-Dist: fairchem-core; extra == "all"
31
43
  Dynamic: license-file
32
44
 
33
45
  <div style="display: flex; align-items: center;">
@@ -50,6 +62,7 @@ Using `mdinterface` you can:
50
62
  - Import common molecules/metals/polymers with pre-defined classical force fields parameters from the database, or automatically generate new OPLS-AA force field parameters using [LigParGen](https://github.com/Isra3l/ligpargen).
51
63
  - Generate polymer chains of any length from a starting monomer.
52
64
  - Estimate the RESP charges of molecules using the [PySCF electronic structure code](https://github.com/pyscf/pyscf).
65
+ - Perform Ab Initio Molecular Dynamics (AIMD) simulations using [FAIRChem](https://github.com/facebookresearch/fairchem) machine learning potentials (optional).
53
66
  - Automatically write LAMMPS data files and coefficients, so you can start making them atoms dance as soon as possible!
54
67
  - Integrate your workflow with [MDAnalysis](https://github.com/MDAnalysis/mdanalysis): create your molecules with `mdinterface` and convert them to `mda.Universe` objects with a simple interface.
55
68
 
@@ -79,58 +92,124 @@ BOSSdir = /path/to/your/boss/dir
79
92
 
80
93
  The config directory is found using [`platformdirs`](https://pypi.org/project/platformdirs/) and is OS dependent.
81
94
 
82
- ### RESP charge analysis with PySCF
95
+ #### RESP charge analysis with PySCF
83
96
 
84
97
  To use the RESP charge analysis feature, you need to install [PySCF](https://github.com/pyscf/pyscf) and [PyMBXAS](https://gitlab.com/roncofaber/pymbxas). To my knowledge, the RESP feature is only implemented in [gpu4pyscf](https://github.com/pyscf/gpu4pyscf) at the moment, so follow the repo instructions on how to install it.
85
98
 
86
- ## Installation
99
+ #### AIMD simulations with FAIRChem
87
100
 
88
- ### Install using `pip`
89
-
90
- You can simply install the latest release of the package and all dependencies using:
101
+ For Ab Initio Molecular Dynamics (AIMD) simulations, you need to install [FAIRChem](https://github.com/facebookresearch/fairchem). This provides machine learning potentials for accelerated quantum mechanical simulations. Install it with:
91
102
 
92
103
  ```bash
93
- pip install mdinterface
104
+ pip install fairchem-core
94
105
  ```
95
106
 
96
- ### Install directly the source code
107
+ This functionality is completely optional and the package will work without it for all other features.
108
+
109
+ ## Installation
110
+
111
+ ### System Requirements
112
+
113
+ - **Python**: 3.8 or higher
114
+ - **PACKMOL**: Required for molecular packing (see below)
115
+ - **Operating System**: Linux, macOS, Windows (with some limitations on Windows)
116
+
117
+ ### Core Installation
97
118
 
98
- Alternatively you can obtain `mdinterface` directly from the repository by following these steps:
119
+ #### Option 1: Install from PyPI (Recommended)
99
120
 
100
- Clone the repository in the desired location:
121
+ Install the latest stable release with all core dependencies:
101
122
 
102
123
  ```bash
103
- git clone git@gitlab.com:roncofaber/mdinterface.git
124
+ pip install mdinterface
104
125
  ```
105
126
 
106
- Install the package:
127
+ #### Option 2: Install from Source
128
+
129
+ For the latest development version or to contribute:
107
130
 
108
131
  ```bash
132
+ # Clone the repository
133
+ git clone https://gitlab.com/roncofaber/mdinterface.git
109
134
  cd mdinterface
135
+
136
+ # Install in normal mode
110
137
  pip install .
138
+
139
+ # Or install in development mode (for contributors)
140
+ pip install -e .
111
141
  ```
112
142
 
113
- ### Install a development environment
143
+ ### Installing PACKMOL
114
144
 
115
- If you plan of making changes, clone the package and add it to your development environment with:
145
+ PACKMOL is required for molecular packing and must be installed separately:
116
146
 
147
+ #### Using conda (Recommended):
117
148
  ```bash
118
- pip install --no-build-isolation -e .
149
+ conda install -c conda-forge packmol
119
150
  ```
120
151
 
121
- ### Install optional packages
152
+ #### From source:
153
+ Follow instructions at [https://m3g.github.io/packmol/](https://m3g.github.io/packmol/)
122
154
 
123
- You can install optional dependencies with the following commands:
155
+ ### Optional Dependencies
156
+
157
+ Install additional features as needed:
124
158
 
125
159
  ```bash
126
- # install libarvo to estimate species:
127
- pip install mdinterface[volume] volumes
128
- # install pyscf and pymbxas (you still need gpu4pyscf):
160
+ # RESP charge analysis (requires additional setup)
129
161
  pip install mdinterface[resp]
130
- # install all of the above options:
162
+
163
+ # AIMD simulations with FAIRChem
164
+ pip install mdinterface[aimd]
165
+
166
+ # All optional dependencies
131
167
  pip install mdinterface[all]
132
168
  ```
133
169
 
170
+ ### Verifying Installation
171
+
172
+ Test your installation:
173
+
174
+ ```python
175
+ import mdinterface
176
+ from mdinterface import SimulationBox, Specie
177
+ print(f"mdinterface version: {mdinterface.__version__}")
178
+ ```
179
+
180
+ ### Troubleshooting
181
+
182
+ #### Common Issues:
183
+
184
+ 1. **PACKMOL not found**: Ensure PACKMOL is in your PATH or install via conda
185
+ 2. **Import errors**: Check that all dependencies are properly installed
186
+ 3. **Version conflicts**: Use a clean virtual environment
187
+
188
+ #### Python Environment Setup:
189
+
190
+ We recommend using a virtual environment:
191
+
192
+ ```bash
193
+ # Create virtual environment
194
+ python -m venv mdinterface-env
195
+ source mdinterface-env/bin/activate # On Windows: mdinterface-env\Scripts\activate
196
+
197
+ # Install mdinterface
198
+ pip install mdinterface
199
+ ```
200
+
201
+ #### For conda users:
202
+
203
+ ```bash
204
+ # Create conda environment
205
+ conda create -n mdinterface python=3.10
206
+ conda activate mdinterface
207
+
208
+ # Install dependencies
209
+ conda install -c conda-forge packmol
210
+ pip install mdinterface
211
+ ```
212
+
134
213
  ## Usage
135
214
 
136
215
  Creating a new Specie (with its topology attributes) is as simple as doing:
@@ -1,35 +1,3 @@
1
- Metadata-Version: 2.4
2
- Name: mdinterface
3
- Version: 1.3.0
4
- Summary: Build Interface Systems for Molecular Dynamics Simulations
5
- Home-page: https://gitlab.com/roncofaber/mdinterface
6
- Author: Fabrice Roncoroni
7
- Author-email: fabrice.roncoroni@gmail.com
8
- License: Apache-2.0
9
- Classifier: Programming Language :: Python :: 3
10
- Classifier: License :: OSI Approved :: Apache Software License
11
- Classifier: Operating System :: OS Independent
12
- Classifier: Topic :: Software Development
13
- Classifier: Topic :: Scientific/Engineering
14
- Requires-Python: >=3.8
15
- Description-Content-Type: text/markdown
16
- License-File: LICENSE
17
- Requires-Dist: mdanalysis
18
- Requires-Dist: ase
19
- Requires-Dist: numpy
20
- Requires-Dist: networkx
21
- Requires-Dist: platformdirs
22
- Requires-Dist: configparser
23
- Provides-Extra: volume
24
- Requires-Dist: libarvo; extra == "volume"
25
- Provides-Extra: resp
26
- Requires-Dist: pyscf; extra == "resp"
27
- Requires-Dist: pymbxas; extra == "resp"
28
- Provides-Extra: all
29
- Requires-Dist: libarvo; extra == "all"
30
- Requires-Dist: pyscf; extra == "all"
31
- Dynamic: license-file
32
-
33
1
  <div style="display: flex; align-items: center;">
34
2
  <img src="./assets/mdinterface.png" alt="Logo" width="80" style="margin-right: 10px;">
35
3
  <div style="display: flex; flex-direction: column;">
@@ -50,6 +18,7 @@ Using `mdinterface` you can:
50
18
  - Import common molecules/metals/polymers with pre-defined classical force fields parameters from the database, or automatically generate new OPLS-AA force field parameters using [LigParGen](https://github.com/Isra3l/ligpargen).
51
19
  - Generate polymer chains of any length from a starting monomer.
52
20
  - Estimate the RESP charges of molecules using the [PySCF electronic structure code](https://github.com/pyscf/pyscf).
21
+ - Perform Ab Initio Molecular Dynamics (AIMD) simulations using [FAIRChem](https://github.com/facebookresearch/fairchem) machine learning potentials (optional).
53
22
  - Automatically write LAMMPS data files and coefficients, so you can start making them atoms dance as soon as possible!
54
23
  - Integrate your workflow with [MDAnalysis](https://github.com/MDAnalysis/mdanalysis): create your molecules with `mdinterface` and convert them to `mda.Universe` objects with a simple interface.
55
24
 
@@ -79,58 +48,124 @@ BOSSdir = /path/to/your/boss/dir
79
48
 
80
49
  The config directory is found using [`platformdirs`](https://pypi.org/project/platformdirs/) and is OS dependent.
81
50
 
82
- ### RESP charge analysis with PySCF
51
+ #### RESP charge analysis with PySCF
83
52
 
84
53
  To use the RESP charge analysis feature, you need to install [PySCF](https://github.com/pyscf/pyscf) and [PyMBXAS](https://gitlab.com/roncofaber/pymbxas). To my knowledge, the RESP feature is only implemented in [gpu4pyscf](https://github.com/pyscf/gpu4pyscf) at the moment, so follow the repo instructions on how to install it.
85
54
 
86
- ## Installation
87
-
88
- ### Install using `pip`
55
+ #### AIMD simulations with FAIRChem
89
56
 
90
- You can simply install the latest release of the package and all dependencies using:
57
+ For Ab Initio Molecular Dynamics (AIMD) simulations, you need to install [FAIRChem](https://github.com/facebookresearch/fairchem). This provides machine learning potentials for accelerated quantum mechanical simulations. Install it with:
91
58
 
92
59
  ```bash
93
- pip install mdinterface
60
+ pip install fairchem-core
94
61
  ```
95
62
 
96
- ### Install directly the source code
63
+ This functionality is completely optional and the package will work without it for all other features.
64
+
65
+ ## Installation
66
+
67
+ ### System Requirements
68
+
69
+ - **Python**: 3.8 or higher
70
+ - **PACKMOL**: Required for molecular packing (see below)
71
+ - **Operating System**: Linux, macOS, Windows (with some limitations on Windows)
97
72
 
98
- Alternatively you can obtain `mdinterface` directly from the repository by following these steps:
73
+ ### Core Installation
99
74
 
100
- Clone the repository in the desired location:
75
+ #### Option 1: Install from PyPI (Recommended)
76
+
77
+ Install the latest stable release with all core dependencies:
101
78
 
102
79
  ```bash
103
- git clone git@gitlab.com:roncofaber/mdinterface.git
80
+ pip install mdinterface
104
81
  ```
105
82
 
106
- Install the package:
83
+ #### Option 2: Install from Source
84
+
85
+ For the latest development version or to contribute:
107
86
 
108
87
  ```bash
88
+ # Clone the repository
89
+ git clone https://gitlab.com/roncofaber/mdinterface.git
109
90
  cd mdinterface
91
+
92
+ # Install in normal mode
110
93
  pip install .
94
+
95
+ # Or install in development mode (for contributors)
96
+ pip install -e .
111
97
  ```
112
98
 
113
- ### Install a development environment
99
+ ### Installing PACKMOL
114
100
 
115
- If you plan of making changes, clone the package and add it to your development environment with:
101
+ PACKMOL is required for molecular packing and must be installed separately:
116
102
 
103
+ #### Using conda (Recommended):
117
104
  ```bash
118
- pip install --no-build-isolation -e .
105
+ conda install -c conda-forge packmol
119
106
  ```
120
107
 
121
- ### Install optional packages
108
+ #### From source:
109
+ Follow instructions at [https://m3g.github.io/packmol/](https://m3g.github.io/packmol/)
110
+
111
+ ### Optional Dependencies
122
112
 
123
- You can install optional dependencies with the following commands:
113
+ Install additional features as needed:
124
114
 
125
115
  ```bash
126
- # install libarvo to estimate species:
127
- pip install mdinterface[volume] volumes
128
- # install pyscf and pymbxas (you still need gpu4pyscf):
116
+ # RESP charge analysis (requires additional setup)
129
117
  pip install mdinterface[resp]
130
- # install all of the above options:
118
+
119
+ # AIMD simulations with FAIRChem
120
+ pip install mdinterface[aimd]
121
+
122
+ # All optional dependencies
131
123
  pip install mdinterface[all]
132
124
  ```
133
125
 
126
+ ### Verifying Installation
127
+
128
+ Test your installation:
129
+
130
+ ```python
131
+ import mdinterface
132
+ from mdinterface import SimulationBox, Specie
133
+ print(f"mdinterface version: {mdinterface.__version__}")
134
+ ```
135
+
136
+ ### Troubleshooting
137
+
138
+ #### Common Issues:
139
+
140
+ 1. **PACKMOL not found**: Ensure PACKMOL is in your PATH or install via conda
141
+ 2. **Import errors**: Check that all dependencies are properly installed
142
+ 3. **Version conflicts**: Use a clean virtual environment
143
+
144
+ #### Python Environment Setup:
145
+
146
+ We recommend using a virtual environment:
147
+
148
+ ```bash
149
+ # Create virtual environment
150
+ python -m venv mdinterface-env
151
+ source mdinterface-env/bin/activate # On Windows: mdinterface-env\Scripts\activate
152
+
153
+ # Install mdinterface
154
+ pip install mdinterface
155
+ ```
156
+
157
+ #### For conda users:
158
+
159
+ ```bash
160
+ # Create conda environment
161
+ conda create -n mdinterface python=3.10
162
+ conda activate mdinterface
163
+
164
+ # Install dependencies
165
+ conda install -c conda-forge packmol
166
+ pip install mdinterface
167
+ ```
168
+
134
169
  ## Usage
135
170
 
136
171
  Creating a new Specie (with its topology attributes) is as simple as doing:
Binary file
@@ -6,8 +6,8 @@ Initially developed to construct electrolyte/electrode interfaces, it is also we
6
6
 
7
7
  """
8
8
 
9
- __version__ = '1.3.0'
10
- __date__ = '17 Jul. 2025'
9
+ __version__ = '1.4.0'
10
+ __date__ = '14 Oct. 2025'
11
11
  __author__ = 'Fabrice Roncoroni'
12
12
  __all__ = ['SimulationBox', "Specie", "Polymer"]
13
13
 
@@ -6,6 +6,7 @@ Created on Tue Jan 14 10:23:57 2025
6
6
  @author: roncofaber
7
7
  """
8
8
 
9
+ from typing import List, Optional, Union, Tuple, Dict, Any
9
10
  from mdinterface.io.packmol import header, box_place, fix_place
10
11
  from mdinterface.build.continuum2sim import discretize_concentration
11
12
 
@@ -18,13 +19,129 @@ import subprocess
18
19
 
19
20
  #%%
20
21
 
21
- def make_solvent_box(species, solvent, ions, volume, density, nions, concentration,
22
- conmodel, ion_pos):
23
-
24
- # make sure info is sound
25
- assert not( nions is not None and concentration is not None),\
26
- "'nions' and 'concentration' cannot both be not None"
27
-
22
+ def _validate_solvent_box_parameters(
23
+ nions: Optional[Union[int, List[int]]],
24
+ concentration: Optional[float],
25
+ conmodel: Optional[Dict[int, Tuple[List[float], List[float]]]],
26
+ ions: Optional[List[Any]],
27
+ solvent: Optional[Any],
28
+ density: Optional[float],
29
+ nsolvent: Optional[int] = None
30
+ ) -> None:
31
+ """
32
+ Validate parameter combinations for make_solvent_box function.
33
+
34
+ Raises appropriate errors for invalid parameter combinations.
35
+ """
36
+
37
+ # Basic mutual exclusivity check
38
+ if nions is not None and concentration is not None:
39
+ raise ValueError("Cannot specify both 'nions' and 'concentration'. Use one or the other.")
40
+
41
+ # If concentration model is provided, ions must be provided
42
+ if conmodel is not None and (ions is None or len(ions) == 0):
43
+ raise ValueError("When using 'conmodel', 'ions' must be provided and non-empty.")
44
+
45
+ # If nions is a list, it must match the number of ion species
46
+ if isinstance(nions, (list, tuple)) and ions is not None:
47
+ if len(nions) != len(ions):
48
+ raise ValueError(f"Length of 'nions' ({len(nions)}) must match number of ion species ({len(ions)}).")
49
+
50
+ # Validate density vs nsolvent mutual exclusivity
51
+ if density is not None and nsolvent is not None:
52
+ import warnings
53
+ warnings.warn(
54
+ "Both 'density' and 'nsolvent' are specified. Using 'nsolvent' and ignoring 'density'.",
55
+ UserWarning, stacklevel=4
56
+ )
57
+
58
+ # If solvent density or nsolvent is provided but no solvent, warn the user
59
+ if (density is not None or nsolvent is not None) and solvent is None:
60
+ import warnings
61
+ warnings.warn("Density or nsolvent specified but no solvent provided. Will be ignored.",
62
+ UserWarning, stacklevel=4)
63
+
64
+ # If no solvent and no ions, nothing to do
65
+ if solvent is None and (ions is None or len(ions) == 0):
66
+ import warnings
67
+ warnings.warn("No solvent or ions specified. Empty box will be created.",
68
+ UserWarning, stacklevel=3)
69
+
70
+ def make_solvent_box(
71
+ species: List[Any],
72
+ solvent: Optional[Any],
73
+ ions: Optional[List[Any]],
74
+ volume: List[float],
75
+ density: Optional[float],
76
+ nions: Optional[Union[int, List[int]]],
77
+ concentration: Optional[float],
78
+ conmodel: Optional[Dict[int, Tuple[List[float], List[float]]]],
79
+ ion_pos: Optional[str],
80
+ nsolvent: Optional[int] = None
81
+ ) -> Optional[mda.Universe]:
82
+ """
83
+ Build a solvent box with optional ionic species.
84
+
85
+ This function creates a simulation box containing solvent molecules and ionic species
86
+ using PACKMOL for molecular packing. It supports various placement strategies and
87
+ concentration models.
88
+
89
+ Parameters:
90
+ -----------
91
+ species : list
92
+ List of all available species in the simulation
93
+ solvent : object or None
94
+ Solvent molecule object (e.g., Water). If None, only ions are placed.
95
+ ions : list or None
96
+ List of ionic species to add to the box
97
+ volume : list
98
+ Box dimensions [x, y, z] in Angstroms
99
+ density : float or None
100
+ Solvent density in g/cm³. Ignored if solvent is None or if nsolvent is specified.
101
+ nions : int, list, or None
102
+ Number of each ionic species. Can be:
103
+ - int: Same number for all ion types
104
+ - list: Different number for each ion type (must match len(ions))
105
+ - None: No ions added
106
+ concentration : float or None
107
+ Ionic concentration in Molar. Alternative to nions.
108
+ Cannot be used simultaneously with nions.
109
+ conmodel : dict or None
110
+ Advanced concentration model for spatially varying concentrations.
111
+ Format: {ion_index: (z_coords, concentration_profile)}
112
+ ion_pos : str or None
113
+ Ion placement strategy:
114
+ - "random": Random placement (default)
115
+ - "center": Place all ions at box center
116
+ - "box": Use PACKMOL box placement
117
+ - "left": Constrain to left half of box
118
+ - None: Defaults to "random"
119
+ nsolvent : int or None
120
+ Number of solvent molecules to place. If specified, takes precedence over density.
121
+ Cannot be used simultaneously with density.
122
+
123
+ Returns:
124
+ --------
125
+ MDAnalysis.Universe or None
126
+ Merged universe containing solvent and ions, or None if no components
127
+
128
+ Examples:
129
+ ---------
130
+ # Simple water box with NaCl
131
+ make_solvent_box(species, water, [na, cl], [20, 20, 20], 1.0, [5, 5], None, None, "random")
132
+
133
+ # Concentration-based approach
134
+ make_solvent_box(species, water, [na, cl], [20, 20, 20], 1.0, None, 0.1, None, "random")
135
+
136
+ # Complex polymer solution
137
+ make_solvent_box(species, None, [polymer, hydronium, water], [50, 50, 50], None, [10, 50, 200], None, None, "box")
138
+ """
139
+
140
+ # Validate parameter combinations
141
+ _validate_solvent_box_parameters(nions, concentration, conmodel, ions, solvent, density, nsolvent)
142
+
143
+ # Legacy parameter compatibility is handled in the calling function (simulationbox.py)
144
+
28
145
  # convert concentration to number of ions
29
146
  if concentration is not None:
30
147
  nions = int(concentration*np.prod(volume)*units.mol/((units.m/10)**3))
@@ -40,12 +157,18 @@ def make_solvent_box(species, solvent, ions, volume, density, nions, concentrati
40
157
 
41
158
  # add solvent
42
159
  if solvent is not None:
43
- solvent_volume = 1e-24*np.prod(volume)
44
- mass = solvent.atoms.masses.sum()
160
+ if nsolvent is not None:
161
+ # Use directly specified number of solvent molecules
162
+ nummols = nsolvent
163
+ elif density is not None:
164
+ # Calculate number of solvent molecules from density
165
+ solvent_volume = 1e-24*np.prod(volume)
166
+ mass = solvent.atoms.masses.sum()
167
+ nummols = int(units.mol*density*(1.0/mass)*solvent_volume)
168
+ else:
169
+ # This should be caught by validation, but defensive programming
170
+ raise ValueError("Either 'density' or 'nsolvent' must be specified for solvent placement")
45
171
 
46
- # number of solvent molecules
47
- nummols = int(units.mol*density*(1.0/mass)*solvent_volume)
48
-
49
172
  instructions.append([solvent, nummols, "box"])
50
173
 
51
174
  # generate universe file
@@ -70,9 +193,12 @@ def make_solvent_box(species, solvent, ions, volume, density, nions, concentrati
70
193
 
71
194
  return solution
72
195
 
73
- # populate a box with solvent and ions
74
- def populate_box(volume, instructions, input_file="input_packmol.in",
75
- output_file="system.pdb"):
196
+ def populate_box(
197
+ volume: List[float],
198
+ instructions: List[Tuple[Any, Union[int, List[float]], str]],
199
+ input_file: str = "input_packmol.in",
200
+ output_file: str = "system.pdb"
201
+ ) -> Optional[mda.Universe]:
76
202
 
77
203
  if not instructions:
78
204
  return None
@@ -168,6 +294,7 @@ def make_interface_slab(interface_uc, xsize, ysize, layers=1):
168
294
 
169
295
  #THANKS CHATGPT (but mostly me tbh)
170
296
  def populate_with_ions(ions, nions, volume, ion_pos=False, conmodel=None):
297
+
171
298
  def place_ion(ion, volume, ion_coords, ion_radii, zpos=None, max_attempts=100):
172
299
  ion_radius = ion.estimate_specie_radius()
173
300
  for _ in range(max_attempts):