pack-mm 0.0.14__py3-none-any.whl → 0.0.19__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
pack_mm/cli/packmm.py CHANGED
@@ -52,30 +52,28 @@ def packmm(
52
52
  ),
53
53
  centre: str | None = typer.Option(
54
54
  None,
55
- help="""Centre of the insertion zone in fractional coordinates,
56
- e.g., '0.12,0.4,0.5'.""",
55
+ help="""Centre of the insertion zone, coordinates in Å,
56
+ e.g., '5.0, 5.0, 5.0'.""",
57
57
  ),
58
58
  radius: float | None = typer.Option(
59
59
  None,
60
60
  help="""Radius of the sphere or cylinder in Å,
61
61
  depending on the insertion volume.""",
62
62
  ),
63
- height: float | None = typer.Option(
64
- None, help="Height of the cylinder in fractional coordinates."
65
- ),
63
+ height: float | None = typer.Option(None, help="Height of the cylinder in Å."),
66
64
  a: float | None = typer.Option(
67
65
  None,
68
- help="""Side of the box or semi-axis of the ellipsoid, fractional,
66
+ help="""Side of the box or semi-axis of the ellipsoid, in Å,
69
67
  depends on the insertion method.""",
70
68
  ),
71
69
  b: float | None = typer.Option(
72
70
  None,
73
- help="""Side of the box or semi-axis of the ellipsoid, fractional,
71
+ help="""Side of the box or semi-axis of the ellipsoid, in Å,
74
72
  depends on the insertion method.""",
75
73
  ),
76
74
  c: float | None = typer.Option(
77
75
  None,
78
- help="""Side of the box or semi-axis of the ellipsoid, fractional,
76
+ help="""Side of the box or semi-axis of the ellipsoid, in Å,
79
77
  depends on the insertion method.""",
80
78
  ),
81
79
  device: str = typer.Option(
@@ -86,15 +84,22 @@ def packmm(
86
84
  temperature: float = typer.Option(
87
85
  300.0, help="Temperature for the Monte Carlo acceptance rule."
88
86
  ),
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."),
87
+ cell_a: float = typer.Option(
88
+ 20.0, help="Side of the empty box along the x-axis in Å."
89
+ ),
90
+ cell_b: float = typer.Option(
91
+ 20.0, help="Side of the empty box along the y-axis in Å."
92
+ ),
93
+ cell_c: float = typer.Option(
94
+ 20.0, help="Side of the empty box along the z-axis in Å."
95
+ ),
92
96
  fmax: float = typer.Option(
93
97
  0.1, help="force tollerance for optimisation if needed."
94
98
  ),
95
99
  geometry: bool = typer.Option(
96
100
  True, help="Perform geometry optimization at the end."
97
101
  ),
102
+ out_path: str = typer.Option(".", help="path to save various outputs."),
98
103
  ):
99
104
  """Pack molecules into a system based on the specified parameters."""
100
105
  print("Script called with following input")
@@ -119,6 +124,7 @@ def packmm(
119
124
  print(f"{temperature=}")
120
125
  print(f"{fmax=}")
121
126
  print(f"{geometry=}")
127
+ print(f"{out_path=}")
122
128
  if nmols == -1:
123
129
  print("nothing to do, no molecule to insert")
124
130
  raise typer.Exit(0)
@@ -151,9 +157,10 @@ def packmm(
151
157
  ntries=ntries,
152
158
  fmax=fmax,
153
159
  geometry=geometry,
154
- ca=cell_a,
155
- cb=cell_b,
156
- cc=cell_c,
160
+ cell_a=cell_a,
161
+ cell_b=cell_b,
162
+ cell_c=cell_c,
163
+ out_path=out_path,
157
164
  )
158
165
 
159
166
 
pack_mm/core/core.py CHANGED
@@ -138,28 +138,29 @@ def validate_value(label, x):
138
138
 
139
139
 
140
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:
141
+ system: str = None,
142
+ molecule: str = "H2O",
143
+ nmols: int = -1,
144
+ arch: str = "cpu",
145
+ model: str = "mace_mp",
146
+ device: str = "medium-omat-0",
147
+ where: str = "anywhere",
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 = 2025,
155
+ temperature: float = 300.0,
156
+ ntries: int = 50,
157
+ geometry: bool = False,
158
+ fmax: float = 0.1,
159
+ cell_a: float = None,
160
+ cell_b: float = None,
161
+ cell_c: float = None,
162
+ out_path: str = ".",
163
+ ) -> float:
163
164
  """
164
165
  Pack molecules into a system based on the specified parameters.
165
166
 
@@ -181,7 +182,8 @@ def pack_molecules(
181
182
  temperature (float): Temperature in Kelvin for acceptance probability.
182
183
  ntries (int): Maximum number of attempts to insert each molecule.
183
184
  geometry (bool): Whether to perform geometry optimization after insertion.
184
- ca, cb, cc (float): Cell dimensions if system is empty.
185
+ cell_a, cell_b, cell_c (float): Cell dimensions if system is empty.
186
+ out_path (str): path to save various outputs
185
187
  """
186
188
  kbt = temperature * 8.6173303e-5 # Boltzmann constant in eV/K
187
189
  validate_value("temperature", temperature)
@@ -193,10 +195,10 @@ def pack_molecules(
193
195
  validate_value("box b", b)
194
196
  validate_value("box c", c)
195
197
  validate_value("ntries", ntries)
196
- validate_value("cell box a", ca)
197
- validate_value("cell box b", cb)
198
+ validate_value("cell box cell a", cell_a)
199
+ validate_value("cell box cell b", cell_b)
198
200
  validate_value("nmols", nmols)
199
- validate_value("cell box c", cc)
201
+ validate_value("cell box cell c", cell_c)
200
202
 
201
203
  random.seed(seed)
202
204
 
@@ -204,25 +206,21 @@ def pack_molecules(
204
206
  sys = read(system)
205
207
  sysname = Path(system).stem
206
208
  except Exception:
207
- sys = Atoms(cell=[ca, cb, cc], pbc=[True, True, True])
209
+ sys = Atoms(cell=[cell_a, cell_b, cell_c], pbc=[True, True, True])
208
210
  sysname = "empty"
209
211
 
210
212
  cell = sys.cell.lengths()
211
213
 
212
- # Print initial information
214
+ # Print summary
213
215
  print(f"Inserting {nmols} {molecule} molecules in {sysname}.")
214
216
  print(f"Using {arch} model {model} on {device}.")
215
217
  print(f"Insert in {where}.")
216
218
 
217
- # Set center of insertion region
218
219
  if center is None:
219
220
  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
221
 
223
- # Set parameters based on insertion region
224
222
  if where == "anywhere":
225
- a, b, c = 1, 1, 1
223
+ a, b, c = cell[0], cell[1], cell[2]
226
224
  elif where == "sphere":
227
225
  if radius is None:
228
226
  radius = min(cell) * 0.5
@@ -230,20 +228,22 @@ def pack_molecules(
230
228
  if radius is None:
231
229
  if where == "cylinderZ":
232
230
  radius = min(cell[0], cell[1]) * 0.5
231
+ if height is None:
232
+ height = 0.5 * cell[2]
233
233
  elif where == "cylinderY":
234
234
  radius = min(cell[0], cell[2]) * 0.5
235
+ if height is None:
236
+ height = 0.5 * cell[1]
235
237
  elif where == "cylinderX":
236
238
  radius = min(cell[2], cell[1]) * 0.5
237
- if height is None:
238
- height = 0.5
239
+ if height is None:
240
+ height = 0.5 * cell[0]
239
241
  elif where == "box":
240
- a, b, c = a or 1, b or 1, c or 1
242
+ a, b, c = a or cell[0], b or cell[1], c or cell[2]
241
243
  elif where == "ellipsoid":
242
- a, b, c = a or 0.5, b or 0.5, c or 0.5
244
+ a, b, c = a or cell[0], b or cell[1], c or cell[2]
243
245
 
244
- calc = choose_calculator(
245
- arch=arch, model_path=model, device=device, default_dtype="float64"
246
- )
246
+ calc = choose_calculator(arch=arch, model_path=model, device=device)
247
247
  sys.calc = calc
248
248
 
249
249
  e = sys.get_potential_energy() if len(sys) > 0 else 0.0
@@ -253,7 +253,7 @@ def pack_molecules(
253
253
  accept = False
254
254
  for _itry in range(ntries):
255
255
  mol = load_molecule(molecule)
256
- tv = get_insertion_position(where, center, cell, a, b, c, radius, height)
256
+ tv = get_insertion_position(where, center, a, b, c, radius, height)
257
257
  mol = rotate_molecule(mol)
258
258
  mol.translate(tv)
259
259
 
@@ -274,18 +274,31 @@ def pack_molecules(
274
274
  csys = tsys.copy()
275
275
  e = en
276
276
  print(f"Inserted particle {i + 1}")
277
- write(f"{sysname}+{i + 1}{Path(molecule).stem}.cif", csys)
277
+ write(Path(out_path) / f"{sysname}+{i + 1}{Path(molecule).stem}.cif", csys)
278
278
  else:
279
+ # Things are bad, maybe geomatry optimisation saves us
279
280
  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
281
+ _ = optimize_geometry(
282
+ f"{sysname}+{i + 1}{Path(molecule).stem}.cif",
283
+ device,
284
+ arch,
285
+ model,
286
+ fmax,
287
+ out_path,
282
288
  )
289
+ energy_final = e
283
290
 
284
291
  # Perform final geometry optimization if requested
285
292
  if geometry:
286
- optimize_geometry(
287
- f"{sysname}+{nmols}{Path(molecule).stem}.cif", device, arch, model, fmax
293
+ energy_final = optimize_geometry(
294
+ f"{sysname}+{nmols}{Path(molecule).stem}.cif",
295
+ device,
296
+ arch,
297
+ model,
298
+ fmax,
299
+ out_path,
288
300
  )
301
+ return energy_final
289
302
 
290
303
 
291
304
  def load_molecule(molecule: str):
@@ -299,25 +312,24 @@ def load_molecule(molecule: str):
299
312
  def get_insertion_position(
300
313
  where: str,
301
314
  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,
315
+ a: float = None,
316
+ b: float = None,
317
+ c: float = None,
318
+ radius: float = None,
319
+ height: float = None,
308
320
  ) -> tuple[float, float, float]:
309
321
  """Get a random insertion position based on the region."""
310
322
  if where == "sphere":
311
323
  return random_point_in_sphere(center, radius)
312
324
  if where == "box":
313
- return random_point_in_box(center, cell[0] * a, cell[1] * b, cell[2] * c)
325
+ return random_point_in_box(center, a, b, c)
314
326
  if where == "ellipsoid":
315
- return random_point_in_ellipsoid(center, cell[0] * a, cell[1] * b, cell[2] * c)
327
+ return random_point_in_ellipsoid(center, a, b, c)
316
328
  if where in ["cylinderZ", "cylinderY", "cylinderX"]:
317
329
  axis = where[-1].lower()
318
- return random_point_in_cylinder(center, radius, cell[2] * height, axis)
330
+ return random_point_in_cylinder(center, radius, height, axis)
319
331
  # now is anywhere
320
- return random.random(3) * [a, b, c] * cell
332
+ return random.random(3) * [a, b, c]
321
333
 
322
334
 
323
335
  def rotate_molecule(mol):
@@ -330,16 +342,21 @@ def rotate_molecule(mol):
330
342
 
331
343
 
332
344
  def optimize_geometry(
333
- struct_path: str, device: str, arch: str, model: str, fmax: float
345
+ struct_path: str,
346
+ device: str,
347
+ arch: str,
348
+ model: str,
349
+ fmax: float,
350
+ out_path: str = ".",
334
351
  ) -> float:
335
352
  """Optimize the geometry of a structure."""
336
353
  geo = GeomOpt(
337
354
  struct_path=struct_path,
338
355
  device=device,
339
356
  fmax=fmax,
340
- calc_kwargs={"model_paths": model, "default_dtype": "float64"},
357
+ calc_kwargs={"model_paths": model},
341
358
  filter_kwargs={"hydrostatic_strain": True},
342
359
  )
343
360
  geo.run()
344
- write(f"{struct_path}-opt.cif", geo.struct)
361
+ write(Path(out_path) / f"{struct_path}-opt.cif", geo.struct)
345
362
  return geo.struct.get_potential_energy()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pack-mm
3
- Version: 0.0.14
3
+ Version: 0.0.19
4
4
  Summary: packing materials and molecules in boxes using for machine learnt interatomic potentials
5
5
  Author: Alin M. Elena
6
6
  Classifier: Programming Language :: Python
@@ -0,0 +1,8 @@
1
+ pack_mm-0.0.19.dist-info/METADATA,sha256=XknqobiQ9HNQyOPmGsJ_auICisxR128TXg_0cU4kh8Y,1583
2
+ pack_mm-0.0.19.dist-info/WHEEL,sha256=thaaA2w1JzcGC48WYufAs8nrYZjJm8LqNfnXFOFyCC4,90
3
+ pack_mm-0.0.19.dist-info/entry_points.txt,sha256=ajKA2oehIa_LCVCP2XTRxV0VNgjGl9c2wYkwk0BasrQ,66
4
+ pack_mm-0.0.19.dist-info/licenses/LICENSE,sha256=ZOYkPdn_vQ8wYJqZnjesow79F_grMbVlHcJ9V91G1pE,1100
5
+ pack_mm/__init__.py,sha256=ct7qfCmTDwhLYip6JKYWRLasmmaGYt0ColbK0CpvYZk,150
6
+ pack_mm/cli/packmm.py,sha256=VqumDT_f1Nf1LCZ1WsF5D6MoLmKEQPEimYenibQHIU4,4944
7
+ pack_mm/core/core.py,sha256=RT9EgMkejhMkqVHN0t_Yn8MDXgQDFD_HOw6Sf3pBeSc,11373
8
+ pack_mm-0.0.19.dist-info/RECORD,,
@@ -1,8 +0,0 @@
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,,