pack-mm 0.0.14__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- pack_mm/__init__.py +7 -0
- pack_mm/cli/packmm.py +161 -0
- pack_mm/core/core.py +345 -0
- pack_mm-0.0.14.dist-info/METADATA +36 -0
- pack_mm-0.0.14.dist-info/RECORD +8 -0
- pack_mm-0.0.14.dist-info/WHEEL +4 -0
- pack_mm-0.0.14.dist-info/entry_points.txt +5 -0
- pack_mm-0.0.14.dist-info/licenses/LICENSE +21 -0
pack_mm/__init__.py
ADDED
pack_mm/cli/packmm.py
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
"""Command line for packmm."""
|
2
|
+
|
3
|
+
# Author; alin m elena, alin@elena.re
|
4
|
+
# Contribs;
|
5
|
+
# Date: 22-02-2025
|
6
|
+
# ©alin m elena,
|
7
|
+
from __future__ import annotations
|
8
|
+
|
9
|
+
from enum import Enum
|
10
|
+
|
11
|
+
import typer
|
12
|
+
|
13
|
+
from pack_mm.core.core import pack_molecules
|
14
|
+
|
15
|
+
|
16
|
+
class InsertionMethod(str, Enum):
|
17
|
+
"""Insertion options."""
|
18
|
+
|
19
|
+
ANYWHERE = "anywhere"
|
20
|
+
SPHERE = "sphere"
|
21
|
+
BOX = "box"
|
22
|
+
CYLINDER_Z = "cylinderZ"
|
23
|
+
CYLINDER_Y = "cylinderY"
|
24
|
+
CYLINDER_X = "cylinderX"
|
25
|
+
ELLIPSOID = "ellipsoid"
|
26
|
+
|
27
|
+
|
28
|
+
app = typer.Typer(no_args_is_help=True)
|
29
|
+
|
30
|
+
|
31
|
+
@app.command()
|
32
|
+
def packmm(
|
33
|
+
system: str | None = typer.Option(
|
34
|
+
None,
|
35
|
+
help="""The original box in which you want to add particles.
|
36
|
+
If not provided, an empty box will be created.""",
|
37
|
+
),
|
38
|
+
molecule: str = typer.Option(
|
39
|
+
"H2O",
|
40
|
+
help="""Name of the molecule to be processed, ASE-recognizable or
|
41
|
+
ASE-readable file.""",
|
42
|
+
),
|
43
|
+
nmols: int = typer.Option(-1, help="Target number of molecules to insert."),
|
44
|
+
ntries: int = typer.Option(
|
45
|
+
50, help="Maximum number of attempts to insert each molecule."
|
46
|
+
),
|
47
|
+
seed: int = typer.Option(2025, help="Random seed for reproducibility."),
|
48
|
+
where: InsertionMethod = typer.Option(
|
49
|
+
InsertionMethod.ANYWHERE,
|
50
|
+
help="""Where to insert the molecule. Choices: 'anywhere', 'sphere',
|
51
|
+
'box', 'cylinderZ', 'cylinderY', 'cylinderX', 'ellipsoid'.""",
|
52
|
+
),
|
53
|
+
centre: str | None = typer.Option(
|
54
|
+
None,
|
55
|
+
help="""Centre of the insertion zone in fractional coordinates,
|
56
|
+
e.g., '0.12,0.4,0.5'.""",
|
57
|
+
),
|
58
|
+
radius: float | None = typer.Option(
|
59
|
+
None,
|
60
|
+
help="""Radius of the sphere or cylinder in Å,
|
61
|
+
depending on the insertion volume.""",
|
62
|
+
),
|
63
|
+
height: float | None = typer.Option(
|
64
|
+
None, help="Height of the cylinder in fractional coordinates."
|
65
|
+
),
|
66
|
+
a: float | None = typer.Option(
|
67
|
+
None,
|
68
|
+
help="""Side of the box or semi-axis of the ellipsoid, fractional,
|
69
|
+
depends on the insertion method.""",
|
70
|
+
),
|
71
|
+
b: float | None = typer.Option(
|
72
|
+
None,
|
73
|
+
help="""Side of the box or semi-axis of the ellipsoid, fractional,
|
74
|
+
depends on the insertion method.""",
|
75
|
+
),
|
76
|
+
c: float | None = typer.Option(
|
77
|
+
None,
|
78
|
+
help="""Side of the box or semi-axis of the ellipsoid, fractional,
|
79
|
+
depends on the insertion method.""",
|
80
|
+
),
|
81
|
+
device: str = typer.Option(
|
82
|
+
"cpu", help="Device to run calculations on (e.g., 'cpu' or 'cuda')."
|
83
|
+
),
|
84
|
+
model: str = typer.Option("medium-omat-0", help="ML model to use."),
|
85
|
+
arch: str = typer.Option("mace_mp", help="MLIP architecture to use."),
|
86
|
+
temperature: float = typer.Option(
|
87
|
+
300.0, help="Temperature for the Monte Carlo acceptance rule."
|
88
|
+
),
|
89
|
+
cell_a: float = typer.Option(20.0, help="Side of the empty box along the x-axis."),
|
90
|
+
cell_b: float = typer.Option(20.0, help="Side of the empty box along the y-axis."),
|
91
|
+
cell_c: float = typer.Option(20.0, help="Side of the empty box along the z-axis."),
|
92
|
+
fmax: float = typer.Option(
|
93
|
+
0.1, help="force tollerance for optimisation if needed."
|
94
|
+
),
|
95
|
+
geometry: bool = typer.Option(
|
96
|
+
True, help="Perform geometry optimization at the end."
|
97
|
+
),
|
98
|
+
):
|
99
|
+
"""Pack molecules into a system based on the specified parameters."""
|
100
|
+
print("Script called with following input")
|
101
|
+
print(f"{system=}")
|
102
|
+
print(f"{nmols=}")
|
103
|
+
print(f"{molecule=}")
|
104
|
+
print(f"{ntries=}")
|
105
|
+
print(f"{seed=}")
|
106
|
+
print(f"where={where.value}")
|
107
|
+
print(f"{centre=}")
|
108
|
+
print(f"{radius=}")
|
109
|
+
print(f"{height=}")
|
110
|
+
print(f"{a=}")
|
111
|
+
print(f"{b=}")
|
112
|
+
print(f"{c=}")
|
113
|
+
print(f"{cell_a=}")
|
114
|
+
print(f"{cell_b=}")
|
115
|
+
print(f"{cell_c=}")
|
116
|
+
print(f"{arch=}")
|
117
|
+
print(f"{model=}")
|
118
|
+
print(f"{device=}")
|
119
|
+
print(f"{temperature=}")
|
120
|
+
print(f"{fmax=}")
|
121
|
+
print(f"{geometry=}")
|
122
|
+
if nmols == -1:
|
123
|
+
print("nothing to do, no molecule to insert")
|
124
|
+
raise typer.Exit(0)
|
125
|
+
|
126
|
+
center = centre
|
127
|
+
if centre:
|
128
|
+
center = tuple(map(float, centre.split(",")))
|
129
|
+
lc = [x < 0.0 for x in center]
|
130
|
+
if len(center) != 3 or any(lc):
|
131
|
+
err = "Invalid centre 3 coordinates expected!"
|
132
|
+
print(f"{err}")
|
133
|
+
raise Exception("Invalid centre 3 coordinates expected!")
|
134
|
+
|
135
|
+
pack_molecules(
|
136
|
+
system=system,
|
137
|
+
molecule=molecule,
|
138
|
+
nmols=nmols,
|
139
|
+
arch=arch,
|
140
|
+
model=model,
|
141
|
+
device=device,
|
142
|
+
where=where,
|
143
|
+
center=center,
|
144
|
+
radius=radius,
|
145
|
+
height=height,
|
146
|
+
a=a,
|
147
|
+
b=b,
|
148
|
+
c=c,
|
149
|
+
seed=seed,
|
150
|
+
temperature=temperature,
|
151
|
+
ntries=ntries,
|
152
|
+
fmax=fmax,
|
153
|
+
geometry=geometry,
|
154
|
+
ca=cell_a,
|
155
|
+
cb=cell_b,
|
156
|
+
cc=cell_c,
|
157
|
+
)
|
158
|
+
|
159
|
+
|
160
|
+
if __name__ == "__main__":
|
161
|
+
app()
|
pack_mm/core/core.py
ADDED
@@ -0,0 +1,345 @@
|
|
1
|
+
# Author; alin m elena, alin@elena.re
|
2
|
+
# Contribs;
|
3
|
+
# Date: 16-11-2024
|
4
|
+
# ©alin m elena,
|
5
|
+
"""pack molecules inside various shapes."""
|
6
|
+
|
7
|
+
from __future__ import annotations
|
8
|
+
|
9
|
+
from pathlib import Path
|
10
|
+
|
11
|
+
from ase import Atoms
|
12
|
+
from ase.build import molecule as build_molecule
|
13
|
+
from ase.io import read, write
|
14
|
+
from janus_core.calculations.geom_opt import GeomOpt
|
15
|
+
from janus_core.helpers.mlip_calculators import choose_calculator
|
16
|
+
from numpy import cos, exp, pi, random, sin, sqrt
|
17
|
+
|
18
|
+
|
19
|
+
def random_point_in_sphere(c: (float, float, float), r: float) -> (float, float, float):
|
20
|
+
"""
|
21
|
+
Generate a random point inside a sphere of radius r, centered at c.
|
22
|
+
|
23
|
+
Parameters
|
24
|
+
----------
|
25
|
+
c (tuple): The center of the sphere as (x, y, z).
|
26
|
+
r (float): The radius of the sphere.
|
27
|
+
|
28
|
+
Returns
|
29
|
+
-------
|
30
|
+
tuple: A point (x, y, z) inside the sphere.
|
31
|
+
"""
|
32
|
+
rad = r * random.rand() ** (1 / 3)
|
33
|
+
|
34
|
+
theta = random.uniform(0, 2 * pi)
|
35
|
+
phi = random.uniform(0, pi)
|
36
|
+
|
37
|
+
x = c[0] + rad * sin(phi) * cos(theta)
|
38
|
+
y = c[1] + rad * sin(phi) * sin(theta)
|
39
|
+
z = c[2] + rad * cos(phi)
|
40
|
+
|
41
|
+
return (x, y, z)
|
42
|
+
|
43
|
+
|
44
|
+
def random_point_in_ellipsoid(
|
45
|
+
d: (float, float, float), a: float, b: float, c: float
|
46
|
+
) -> (float, float, float):
|
47
|
+
"""
|
48
|
+
Generate a random point inside an ellipsoid with axes a, b, c, centered at d.
|
49
|
+
|
50
|
+
Parameters
|
51
|
+
----------
|
52
|
+
d (tuple): The center of the ellipsoid as (x, y, z).
|
53
|
+
a (float): The semi-axis length of the ellipsoid along the x-axis.
|
54
|
+
b (float): The semi-axis length of the ellipsoid along the y-axis.
|
55
|
+
c (float): The semi-axis length of the ellipsoid along the z-axis.
|
56
|
+
|
57
|
+
Returns
|
58
|
+
-------
|
59
|
+
tuple: A point (x, y, z) inside the ellipsoid.
|
60
|
+
"""
|
61
|
+
theta = random.uniform(0, 2 * pi)
|
62
|
+
phi = random.uniform(0, pi)
|
63
|
+
rad = random.rand() ** (1 / 3)
|
64
|
+
|
65
|
+
x = d[0] + a * rad * sin(phi) * cos(theta)
|
66
|
+
y = d[1] + b * rad * sin(phi) * sin(theta)
|
67
|
+
z = d[2] + c * rad * cos(phi)
|
68
|
+
|
69
|
+
return (x, y, z)
|
70
|
+
|
71
|
+
|
72
|
+
def random_point_in_box(
|
73
|
+
d: (float, float, float), a: float, b: float, c: float
|
74
|
+
) -> (float, float, float):
|
75
|
+
"""
|
76
|
+
Generate a random point inside a box with sides a, b, c, centered at d.
|
77
|
+
|
78
|
+
Parameters
|
79
|
+
----------
|
80
|
+
d (tuple): The center of the box as (x, y, z).
|
81
|
+
a (float): The length of the box along the x-axis.
|
82
|
+
b (float): The length of the box along the y-axis.
|
83
|
+
c (float): The length of the box along the z-axis.
|
84
|
+
|
85
|
+
Returns
|
86
|
+
-------
|
87
|
+
tuple: A point (x, y, z) inside the box.
|
88
|
+
"""
|
89
|
+
x = d[0] + random.uniform(-a * 0.5, a * 0.5)
|
90
|
+
y = d[1] + random.uniform(-b * 0.5, b * 0.5)
|
91
|
+
z = d[2] + random.uniform(-c * 0.5, c * 0.5)
|
92
|
+
|
93
|
+
return (x, y, z)
|
94
|
+
|
95
|
+
|
96
|
+
def random_point_in_cylinder(
|
97
|
+
c: (float, float, float), r: float, h: float, d: str
|
98
|
+
) -> (float, float, float):
|
99
|
+
"""
|
100
|
+
Generate a random point inside a cylinder with radius r and height h, centered at c.
|
101
|
+
|
102
|
+
Parameters
|
103
|
+
----------
|
104
|
+
c (tuple): The center of the cylinder as (x, y, z).
|
105
|
+
r (float): The radius of the cylinder's base.
|
106
|
+
h (float): The height of the cylinder.
|
107
|
+
direction (str): direction along which cylinger is oriented
|
108
|
+
|
109
|
+
Returns
|
110
|
+
-------
|
111
|
+
tuple: A point (x, y, z) inside the cylinder.
|
112
|
+
"""
|
113
|
+
theta = random.uniform(0, 2 * pi)
|
114
|
+
rad = r * sqrt(random.rand())
|
115
|
+
|
116
|
+
if d == "z":
|
117
|
+
z = c[2] + random.uniform(-h * 0.5, h * 0.5)
|
118
|
+
x = c[0] + rad * cos(theta)
|
119
|
+
y = c[1] + rad * sin(theta)
|
120
|
+
elif d == "y":
|
121
|
+
y = c[1] + random.uniform(-h * 0.5, h * 0.5)
|
122
|
+
x = c[0] + rad * cos(theta)
|
123
|
+
z = c[2] + rad * sin(theta)
|
124
|
+
elif d == "x":
|
125
|
+
x = c[0] + random.uniform(-h * 0.5, h * 0.5)
|
126
|
+
y = c[1] + rad * sin(theta)
|
127
|
+
z = c[2] + rad * cos(theta)
|
128
|
+
|
129
|
+
return (x, y, z)
|
130
|
+
|
131
|
+
|
132
|
+
def validate_value(label, x):
|
133
|
+
"""Validate input value, and raise an exception."""
|
134
|
+
if x is not None and x < 0.0:
|
135
|
+
err = f"Invalid {label}, needs to be positive"
|
136
|
+
print(err)
|
137
|
+
raise Exception(err)
|
138
|
+
|
139
|
+
|
140
|
+
def pack_molecules(
|
141
|
+
system: str | None,
|
142
|
+
molecule: str,
|
143
|
+
nmols: int,
|
144
|
+
arch: str,
|
145
|
+
model: str,
|
146
|
+
device: str,
|
147
|
+
where: str,
|
148
|
+
center: tuple[float, float, float] | None,
|
149
|
+
radius: float | None,
|
150
|
+
height: float | None,
|
151
|
+
a: float | None,
|
152
|
+
b: float | None,
|
153
|
+
c: float | None,
|
154
|
+
seed: int,
|
155
|
+
temperature: float,
|
156
|
+
ntries: int,
|
157
|
+
geometry: bool,
|
158
|
+
fmax: float,
|
159
|
+
ca: float,
|
160
|
+
cb: float,
|
161
|
+
cc: float,
|
162
|
+
) -> None:
|
163
|
+
"""
|
164
|
+
Pack molecules into a system based on the specified parameters.
|
165
|
+
|
166
|
+
Parameters
|
167
|
+
----------
|
168
|
+
system (str): Path to the system file or name of the system.
|
169
|
+
molecule (str): Path to the molecule file or name of the molecule.
|
170
|
+
nmols (int): Number of molecules to insert.
|
171
|
+
arch (str): Architecture for the calculator.
|
172
|
+
model (str): Path to the model file.
|
173
|
+
device (str): Device to run calculations on (e.g., "cpu" or "cuda").
|
174
|
+
where (str): Region to insert molecules ("anywhere",
|
175
|
+
"sphere", "cylinderZ", etc.).
|
176
|
+
center (Optional[Tuple[float, float, float]]): Center of the insertion region.
|
177
|
+
radius (Optional[float]): Radius for spherical or cylindrical insertion.
|
178
|
+
height (Optional[float]): Height for cylindrical insertion.
|
179
|
+
a, b, c (Optional[float]): Parameters for box or ellipsoid insertion.
|
180
|
+
seed (int): Random seed for reproducibility.
|
181
|
+
temperature (float): Temperature in Kelvin for acceptance probability.
|
182
|
+
ntries (int): Maximum number of attempts to insert each molecule.
|
183
|
+
geometry (bool): Whether to perform geometry optimization after insertion.
|
184
|
+
ca, cb, cc (float): Cell dimensions if system is empty.
|
185
|
+
"""
|
186
|
+
kbt = temperature * 8.6173303e-5 # Boltzmann constant in eV/K
|
187
|
+
validate_value("temperature", temperature)
|
188
|
+
validate_value("radius", radius)
|
189
|
+
validate_value("height", height)
|
190
|
+
validate_value("fmax", fmax)
|
191
|
+
validate_value("seed", seed)
|
192
|
+
validate_value("box a", a)
|
193
|
+
validate_value("box b", b)
|
194
|
+
validate_value("box c", c)
|
195
|
+
validate_value("ntries", ntries)
|
196
|
+
validate_value("cell box a", ca)
|
197
|
+
validate_value("cell box b", cb)
|
198
|
+
validate_value("nmols", nmols)
|
199
|
+
validate_value("cell box c", cc)
|
200
|
+
|
201
|
+
random.seed(seed)
|
202
|
+
|
203
|
+
try:
|
204
|
+
sys = read(system)
|
205
|
+
sysname = Path(system).stem
|
206
|
+
except Exception:
|
207
|
+
sys = Atoms(cell=[ca, cb, cc], pbc=[True, True, True])
|
208
|
+
sysname = "empty"
|
209
|
+
|
210
|
+
cell = sys.cell.lengths()
|
211
|
+
|
212
|
+
# Print initial information
|
213
|
+
print(f"Inserting {nmols} {molecule} molecules in {sysname}.")
|
214
|
+
print(f"Using {arch} model {model} on {device}.")
|
215
|
+
print(f"Insert in {where}.")
|
216
|
+
|
217
|
+
# Set center of insertion region
|
218
|
+
if center is None:
|
219
|
+
center = (cell[0] * 0.5, cell[1] * 0.5, cell[2] * 0.5)
|
220
|
+
else:
|
221
|
+
center = tuple(ci * cell[i] for i, ci in enumerate(center))
|
222
|
+
|
223
|
+
# Set parameters based on insertion region
|
224
|
+
if where == "anywhere":
|
225
|
+
a, b, c = 1, 1, 1
|
226
|
+
elif where == "sphere":
|
227
|
+
if radius is None:
|
228
|
+
radius = min(cell) * 0.5
|
229
|
+
elif where in ["cylinderZ", "cylinderY", "cylinderX"]:
|
230
|
+
if radius is None:
|
231
|
+
if where == "cylinderZ":
|
232
|
+
radius = min(cell[0], cell[1]) * 0.5
|
233
|
+
elif where == "cylinderY":
|
234
|
+
radius = min(cell[0], cell[2]) * 0.5
|
235
|
+
elif where == "cylinderX":
|
236
|
+
radius = min(cell[2], cell[1]) * 0.5
|
237
|
+
if height is None:
|
238
|
+
height = 0.5
|
239
|
+
elif where == "box":
|
240
|
+
a, b, c = a or 1, b or 1, c or 1
|
241
|
+
elif where == "ellipsoid":
|
242
|
+
a, b, c = a or 0.5, b or 0.5, c or 0.5
|
243
|
+
|
244
|
+
calc = choose_calculator(
|
245
|
+
arch=arch, model_path=model, device=device, default_dtype="float64"
|
246
|
+
)
|
247
|
+
sys.calc = calc
|
248
|
+
|
249
|
+
e = sys.get_potential_energy() if len(sys) > 0 else 0.0
|
250
|
+
|
251
|
+
csys = sys.copy()
|
252
|
+
for i in range(nmols):
|
253
|
+
accept = False
|
254
|
+
for _itry in range(ntries):
|
255
|
+
mol = load_molecule(molecule)
|
256
|
+
tv = get_insertion_position(where, center, cell, a, b, c, radius, height)
|
257
|
+
mol = rotate_molecule(mol)
|
258
|
+
mol.translate(tv)
|
259
|
+
|
260
|
+
tsys = csys.copy() + mol.copy()
|
261
|
+
tsys.calc = calc
|
262
|
+
en = tsys.get_potential_energy()
|
263
|
+
de = en - e
|
264
|
+
|
265
|
+
acc = exp(-de / kbt)
|
266
|
+
u = random.random()
|
267
|
+
print(f"Old energy={e}, new energy={en}, {de=}, {acc=}, random={u}")
|
268
|
+
|
269
|
+
if u <= acc:
|
270
|
+
accept = True
|
271
|
+
break
|
272
|
+
|
273
|
+
if accept:
|
274
|
+
csys = tsys.copy()
|
275
|
+
e = en
|
276
|
+
print(f"Inserted particle {i + 1}")
|
277
|
+
write(f"{sysname}+{i + 1}{Path(molecule).stem}.cif", csys)
|
278
|
+
else:
|
279
|
+
print(f"Failed to insert particle {i + 1} after {ntries} tries")
|
280
|
+
optimize_geometry(
|
281
|
+
f"{sysname}+{i + 1}{Path(molecule).stem}.cif", device, arch, model, fmax
|
282
|
+
)
|
283
|
+
|
284
|
+
# Perform final geometry optimization if requested
|
285
|
+
if geometry:
|
286
|
+
optimize_geometry(
|
287
|
+
f"{sysname}+{nmols}{Path(molecule).stem}.cif", device, arch, model, fmax
|
288
|
+
)
|
289
|
+
|
290
|
+
|
291
|
+
def load_molecule(molecule: str):
|
292
|
+
"""Load a molecule from a file or build it."""
|
293
|
+
try:
|
294
|
+
return build_molecule(molecule)
|
295
|
+
except KeyError:
|
296
|
+
return read(molecule)
|
297
|
+
|
298
|
+
|
299
|
+
def get_insertion_position(
|
300
|
+
where: str,
|
301
|
+
center: tuple[float, float, float],
|
302
|
+
cell: list[float],
|
303
|
+
a: float,
|
304
|
+
b: float,
|
305
|
+
c: float,
|
306
|
+
radius: float | None,
|
307
|
+
height: float | None,
|
308
|
+
) -> tuple[float, float, float]:
|
309
|
+
"""Get a random insertion position based on the region."""
|
310
|
+
if where == "sphere":
|
311
|
+
return random_point_in_sphere(center, radius)
|
312
|
+
if where == "box":
|
313
|
+
return random_point_in_box(center, cell[0] * a, cell[1] * b, cell[2] * c)
|
314
|
+
if where == "ellipsoid":
|
315
|
+
return random_point_in_ellipsoid(center, cell[0] * a, cell[1] * b, cell[2] * c)
|
316
|
+
if where in ["cylinderZ", "cylinderY", "cylinderX"]:
|
317
|
+
axis = where[-1].lower()
|
318
|
+
return random_point_in_cylinder(center, radius, cell[2] * height, axis)
|
319
|
+
# now is anywhere
|
320
|
+
return random.random(3) * [a, b, c] * cell
|
321
|
+
|
322
|
+
|
323
|
+
def rotate_molecule(mol):
|
324
|
+
"""Rotate a molecule randomly."""
|
325
|
+
ang = random.random(3)
|
326
|
+
mol.euler_rotate(
|
327
|
+
phi=ang[0] * 360, theta=ang[1] * 180, psi=ang[2] * 360, center=(0.0, 0.0, 0.0)
|
328
|
+
)
|
329
|
+
return mol
|
330
|
+
|
331
|
+
|
332
|
+
def optimize_geometry(
|
333
|
+
struct_path: str, device: str, arch: str, model: str, fmax: float
|
334
|
+
) -> float:
|
335
|
+
"""Optimize the geometry of a structure."""
|
336
|
+
geo = GeomOpt(
|
337
|
+
struct_path=struct_path,
|
338
|
+
device=device,
|
339
|
+
fmax=fmax,
|
340
|
+
calc_kwargs={"model_paths": model, "default_dtype": "float64"},
|
341
|
+
filter_kwargs={"hydrostatic_strain": True},
|
342
|
+
)
|
343
|
+
geo.run()
|
344
|
+
write(f"{struct_path}-opt.cif", geo.struct)
|
345
|
+
return geo.struct.get_potential_energy()
|
@@ -0,0 +1,36 @@
|
|
1
|
+
Metadata-Version: 2.1
|
2
|
+
Name: pack-mm
|
3
|
+
Version: 0.0.14
|
4
|
+
Summary: packing materials and molecules in boxes using for machine learnt interatomic potentials
|
5
|
+
Author: Alin M. Elena
|
6
|
+
Classifier: Programming Language :: Python
|
7
|
+
Classifier: Programming Language :: Python :: 3.10
|
8
|
+
Classifier: Programming Language :: Python :: 3.11
|
9
|
+
Classifier: Programming Language :: Python :: 3.12
|
10
|
+
Classifier: Intended Audience :: Science/Research
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
12
|
+
Classifier: Natural Language :: English
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
14
|
+
Project-URL: Repository, https://github.com/ddmms/pack-mm/
|
15
|
+
Project-URL: Documentation, https://ddmms.github.io/pack-mm/
|
16
|
+
Requires-Python: >=3.10
|
17
|
+
Requires-Dist: janus-core>=0.7.2
|
18
|
+
Requires-Dist: typer<1.0.0,>=0.12.5
|
19
|
+
Requires-Dist: typer-config<2.0.0,>=1.4.2
|
20
|
+
Description-Content-Type: text/markdown
|
21
|
+
|
22
|
+
# pack materials and molecules
|
23
|
+
|
24
|
+
[![Python versions][python-badge]][python-link]
|
25
|
+
[![Build Status][ci-badge]][ci-link]
|
26
|
+
[![Coverage Status][cov-badge]][cov-link]
|
27
|
+
[![License][license-badge]][license-link]
|
28
|
+
|
29
|
+
[python-badge]: https://img.shields.io/pypi/pyversions/pack-mm.svg
|
30
|
+
[python-link]: https://pypi.org/project/pack-mm/
|
31
|
+
[ci-badge]: https://github.com/ddmms/pack-mm/actions/workflows/build.yml/badge.svg?branch=main
|
32
|
+
[ci-link]: https://github.com/ddmms/pack-mm/actions
|
33
|
+
[cov-badge]: https://coveralls.io/repos/github/ddmms/pack-mm/badge.svg?branch=main
|
34
|
+
[cov-link]: https://coveralls.io/github/ddmms/pack-mm?branch=main
|
35
|
+
[license-badge]: https://img.shields.io/badge/License-MIT-yellow.svg
|
36
|
+
[license-link]: https://opensource.org/license/MIT
|
@@ -0,0 +1,8 @@
|
|
1
|
+
pack_mm-0.0.14.dist-info/METADATA,sha256=KOiX1eZqUv1OmoKdtpFyUC_ueiJ3BYGBhZjv6D8ZPMg,1583
|
2
|
+
pack_mm-0.0.14.dist-info/WHEEL,sha256=thaaA2w1JzcGC48WYufAs8nrYZjJm8LqNfnXFOFyCC4,90
|
3
|
+
pack_mm-0.0.14.dist-info/entry_points.txt,sha256=ajKA2oehIa_LCVCP2XTRxV0VNgjGl9c2wYkwk0BasrQ,66
|
4
|
+
pack_mm-0.0.14.dist-info/licenses/LICENSE,sha256=ZOYkPdn_vQ8wYJqZnjesow79F_grMbVlHcJ9V91G1pE,1100
|
5
|
+
pack_mm/__init__.py,sha256=ct7qfCmTDwhLYip6JKYWRLasmmaGYt0ColbK0CpvYZk,150
|
6
|
+
pack_mm/cli/packmm.py,sha256=FWiBUQBG6Z5Vi5A1VH9DYUn8iBwIs4NbFR5a8mPtEpM,4797
|
7
|
+
pack_mm/core/core.py,sha256=gP8j1NJg3_8dj4it3V2Z80dbAKhy0emwUjd_-wuKvws,10839
|
8
|
+
pack_mm-0.0.14.dist-info/RECORD,,
|
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2024 data-driven materials and molecular science
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|