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

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.
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,,