pack-mm 0.0.21__py3-none-any.whl → 0.0.22__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 +45 -4
- pack_mm/core/core.py +178 -43
- {pack_mm-0.0.21.dist-info → pack_mm-0.0.22.dist-info}/METADATA +3 -3
- pack_mm-0.0.22.dist-info/RECORD +8 -0
- pack_mm-0.0.21.dist-info/RECORD +0 -8
- {pack_mm-0.0.21.dist-info → pack_mm-0.0.22.dist-info}/WHEEL +0 -0
- {pack_mm-0.0.21.dist-info → pack_mm-0.0.22.dist-info}/entry_points.txt +0 -0
- {pack_mm-0.0.21.dist-info → pack_mm-0.0.22.dist-info}/licenses/LICENSE +0 -0
pack_mm/cli/packmm.py
CHANGED
@@ -25,6 +25,22 @@ class InsertionMethod(str, Enum):
|
|
25
25
|
ELLIPSOID = "ellipsoid"
|
26
26
|
|
27
27
|
|
28
|
+
class InsertionStrategy(str, Enum):
|
29
|
+
"""Insertion options."""
|
30
|
+
|
31
|
+
# propose randomly a point
|
32
|
+
MC = "mc"
|
33
|
+
# hybrid monte carlo
|
34
|
+
HMC = "hmc"
|
35
|
+
|
36
|
+
|
37
|
+
class RelaxStrategy(str, Enum):
|
38
|
+
"""Relaxation options."""
|
39
|
+
|
40
|
+
GEOMETRY_OPTIMISATION = "geometry_optimisation"
|
41
|
+
MD = "md"
|
42
|
+
|
43
|
+
|
28
44
|
app = typer.Typer(no_args_is_help=True)
|
29
45
|
|
30
46
|
|
@@ -44,12 +60,26 @@ def packmm(
|
|
44
60
|
ntries: int = typer.Option(
|
45
61
|
50, help="Maximum number of attempts to insert each molecule."
|
46
62
|
),
|
63
|
+
every: int = typer.Option(
|
64
|
+
-1, help="Run MD-NVE or Geometry optimisation everyth insertion."
|
65
|
+
),
|
47
66
|
seed: int = typer.Option(2025, help="Random seed for reproducibility."),
|
67
|
+
md_steps: int = typer.Option(10, help="Number of steps to run MD."),
|
68
|
+
md_timestep: float = typer.Option(1.0, help="Timestep for MD integration, in fs."),
|
48
69
|
where: InsertionMethod = typer.Option(
|
49
70
|
InsertionMethod.ANYWHERE,
|
50
71
|
help="""Where to insert the molecule. Choices: 'anywhere', 'sphere',
|
51
72
|
'box', 'cylinderZ', 'cylinderY', 'cylinderX', 'ellipsoid'.""",
|
52
73
|
),
|
74
|
+
insert_strategy: InsertionStrategy = typer.Option(
|
75
|
+
InsertionStrategy.MC,
|
76
|
+
help="""How to insert a new molecule. Choices: 'mc', 'hmc',""",
|
77
|
+
),
|
78
|
+
relax_strategy: RelaxStrategy = typer.Option(
|
79
|
+
RelaxStrategy.GEOMETRY_OPTIMISATION,
|
80
|
+
help="""How to relax the system to get more favourable structures.
|
81
|
+
Choices: 'geometry_optimisation', 'md',""",
|
82
|
+
),
|
53
83
|
centre: str | None = typer.Option(
|
54
84
|
None,
|
55
85
|
help="""Centre of the insertion zone, coordinates in Å,
|
@@ -84,6 +114,9 @@ def packmm(
|
|
84
114
|
temperature: float = typer.Option(
|
85
115
|
300.0, help="Temperature for the Monte Carlo acceptance rule."
|
86
116
|
),
|
117
|
+
md_temperature: float = typer.Option(
|
118
|
+
100.0, help="Temperature for the Molecular dynamics relaxation."
|
119
|
+
),
|
87
120
|
cell_a: float = typer.Option(
|
88
121
|
20.0, help="Side of the empty box along the x-axis in Å."
|
89
122
|
),
|
@@ -125,6 +158,12 @@ def packmm(
|
|
125
158
|
print(f"{fmax=}")
|
126
159
|
print(f"{geometry=}")
|
127
160
|
print(f"{out_path=}")
|
161
|
+
print(f"{every=}")
|
162
|
+
print(f"insert_strategy={insert_strategy.value}")
|
163
|
+
print(f"relax_strategy={relax_strategy.value}")
|
164
|
+
print(f"{md_steps=}")
|
165
|
+
print(f"{md_timestep=}")
|
166
|
+
print(f"{md_temperature=}")
|
128
167
|
if nmols == -1:
|
129
168
|
print("nothing to do, no molecule to insert")
|
130
169
|
raise typer.Exit(0)
|
@@ -161,8 +200,10 @@ def packmm(
|
|
161
200
|
cell_b=cell_b,
|
162
201
|
cell_c=cell_c,
|
163
202
|
out_path=out_path,
|
203
|
+
every=every,
|
204
|
+
relax_strategy=relax_strategy,
|
205
|
+
insert_strategy=insert_strategy,
|
206
|
+
md_steps=md_steps,
|
207
|
+
md_timestep=md_timestep,
|
208
|
+
md_temperature=md_temperature,
|
164
209
|
)
|
165
|
-
|
166
|
-
|
167
|
-
if __name__ == "__main__":
|
168
|
-
app()
|
pack_mm/core/core.py
CHANGED
@@ -13,6 +13,7 @@ from ase.build import molecule as build_molecule
|
|
13
13
|
from ase.io import read, write
|
14
14
|
from ase.units import kB
|
15
15
|
from janus_core.calculations.geom_opt import GeomOpt
|
16
|
+
from janus_core.calculations.md import NVE
|
16
17
|
from janus_core.helpers.mlip_calculators import choose_calculator
|
17
18
|
from numpy import cos, exp, pi, random, sin, sqrt
|
18
19
|
|
@@ -130,7 +131,7 @@ def random_point_in_cylinder(
|
|
130
131
|
return (x, y, z)
|
131
132
|
|
132
133
|
|
133
|
-
def validate_value(label, x):
|
134
|
+
def validate_value(label: str, x: float | int) -> None:
|
134
135
|
"""Validate input value, and raise an exception."""
|
135
136
|
if x is not None and x < 0.0:
|
136
137
|
err = f"Invalid {label}, needs to be positive"
|
@@ -138,6 +139,52 @@ def validate_value(label, x):
|
|
138
139
|
raise Exception(err)
|
139
140
|
|
140
141
|
|
142
|
+
def set_random_seed(seed: int) -> None:
|
143
|
+
"""Set random seed."""
|
144
|
+
random.seed(seed)
|
145
|
+
|
146
|
+
|
147
|
+
def set_defaults(
|
148
|
+
cell: (float, float, float),
|
149
|
+
centre: (float, float, float) | None = None,
|
150
|
+
where: str | None = None,
|
151
|
+
a: float | None = None,
|
152
|
+
b: float | None = None,
|
153
|
+
c: float | None = None,
|
154
|
+
radius: float | None = None,
|
155
|
+
height: float | None = None,
|
156
|
+
) -> tuple(
|
157
|
+
(float, float, float),
|
158
|
+
float | None,
|
159
|
+
float | None,
|
160
|
+
float | None,
|
161
|
+
float | None,
|
162
|
+
float | None,
|
163
|
+
):
|
164
|
+
"""Set defaults for insertion areas."""
|
165
|
+
if centre is None:
|
166
|
+
centre = (cell[0] * 0.5, cell[1] * 0.5, cell[2] * 0.5)
|
167
|
+
|
168
|
+
if where == "anywhere":
|
169
|
+
a, b, c = cell[0], cell[1], cell[2]
|
170
|
+
elif where == "sphere":
|
171
|
+
radius = radius or min(cell) * 0.5
|
172
|
+
elif where == "cylinderZ":
|
173
|
+
radius = radius or min(cell[0], cell[1]) * 0.5
|
174
|
+
height = height or 0.5 * cell[2]
|
175
|
+
elif where == "cylinderY":
|
176
|
+
radius = radius or min(cell[0], cell[2]) * 0.5
|
177
|
+
height = height or 0.5 * cell[1]
|
178
|
+
elif where == "cylinderX":
|
179
|
+
radius = radius or min(cell[2], cell[1]) * 0.5
|
180
|
+
height = height or 0.5 * cell[0]
|
181
|
+
elif where == "box":
|
182
|
+
a, b, c = a or cell[0], b or cell[1], c or cell[2]
|
183
|
+
elif where == "ellipsoid":
|
184
|
+
a, b, c = a or cell[0] * 0.5, b or cell[1] * 0.5, c or cell[2] * 0.5
|
185
|
+
return (centre, a, b, c, radius, height)
|
186
|
+
|
187
|
+
|
141
188
|
def pack_molecules(
|
142
189
|
system: str = None,
|
143
190
|
molecule: str = "H2O",
|
@@ -161,6 +208,12 @@ def pack_molecules(
|
|
161
208
|
cell_b: float = None,
|
162
209
|
cell_c: float = None,
|
163
210
|
out_path: str = ".",
|
211
|
+
every: int = -1,
|
212
|
+
relax_strategy: str = "geometry_optimisation",
|
213
|
+
insert_strategy: str = "random",
|
214
|
+
md_steps: int = 10,
|
215
|
+
md_timestep: float = 1.0,
|
216
|
+
md_temperature: float = 100.0,
|
164
217
|
) -> float:
|
165
218
|
"""
|
166
219
|
Pack molecules into a system based on the specified parameters.
|
@@ -185,6 +238,14 @@ def pack_molecules(
|
|
185
238
|
geometry (bool): Whether to perform geometry optimization after insertion.
|
186
239
|
cell_a, cell_b, cell_c (float): Cell dimensions if system is empty.
|
187
240
|
out_path (str): path to save various outputs
|
241
|
+
every (int): After how many instertions to do a relaxation,
|
242
|
+
default -1 means none..
|
243
|
+
md_temperature (float): Temperature in Kelvin for MD.
|
244
|
+
md_steps (int): Number of steps for MD.
|
245
|
+
md_timestep (float): Timestep in fs for MD.
|
246
|
+
insert_strategy (str): Insert strategy, "random" or "md"
|
247
|
+
relax_strategy (str): Relax strategy, "geometry_optimisation" or "md"
|
248
|
+
|
188
249
|
"""
|
189
250
|
kbt = temperature * kB
|
190
251
|
validate_value("temperature", temperature)
|
@@ -198,51 +259,31 @@ def pack_molecules(
|
|
198
259
|
validate_value("ntries", ntries)
|
199
260
|
validate_value("cell box cell a", cell_a)
|
200
261
|
validate_value("cell box cell b", cell_b)
|
201
|
-
validate_value("nmols", nmols)
|
202
262
|
validate_value("cell box cell c", cell_c)
|
263
|
+
validate_value("nmols", nmols)
|
264
|
+
validate_value("MD steps", md_steps)
|
265
|
+
validate_value("MD timestep", md_timestep)
|
266
|
+
validate_value("MD temperature", md_temperature)
|
203
267
|
|
204
|
-
|
268
|
+
set_random_seed(seed)
|
205
269
|
|
206
|
-
|
207
|
-
sys = read(system)
|
208
|
-
sysname = Path(system).stem
|
209
|
-
except Exception:
|
270
|
+
if system is None:
|
210
271
|
sys = Atoms(cell=[cell_a, cell_b, cell_c], pbc=[True, True, True])
|
211
|
-
sysname = "
|
212
|
-
|
213
|
-
|
272
|
+
sysname = ""
|
273
|
+
else:
|
274
|
+
sys = read(system)
|
275
|
+
sysname = Path(system).stem + "+"
|
214
276
|
|
215
277
|
# Print summary
|
216
278
|
print(f"Inserting {nmols} {molecule} molecules in {sysname}.")
|
217
279
|
print(f"Using {arch} model {model} on {device}.")
|
218
280
|
print(f"Insert in {where}.")
|
219
281
|
|
220
|
-
|
221
|
-
center = (cell[0] * 0.5, cell[1] * 0.5, cell[2] * 0.5)
|
282
|
+
cell = sys.cell.lengths()
|
222
283
|
|
223
|
-
|
224
|
-
a, b, c
|
225
|
-
|
226
|
-
if radius is None:
|
227
|
-
radius = min(cell) * 0.5
|
228
|
-
elif where in ["cylinderZ", "cylinderY", "cylinderX"]:
|
229
|
-
if radius is None:
|
230
|
-
if where == "cylinderZ":
|
231
|
-
radius = min(cell[0], cell[1]) * 0.5
|
232
|
-
if height is None:
|
233
|
-
height = 0.5 * cell[2]
|
234
|
-
elif where == "cylinderY":
|
235
|
-
radius = min(cell[0], cell[2]) * 0.5
|
236
|
-
if height is None:
|
237
|
-
height = 0.5 * cell[1]
|
238
|
-
elif where == "cylinderX":
|
239
|
-
radius = min(cell[2], cell[1]) * 0.5
|
240
|
-
if height is None:
|
241
|
-
height = 0.5 * cell[0]
|
242
|
-
elif where == "box":
|
243
|
-
a, b, c = a or cell[0], b or cell[1], c or cell[2]
|
244
|
-
elif where == "ellipsoid":
|
245
|
-
a, b, c = a or cell[0], b or cell[1], c or cell[2]
|
284
|
+
center, a, b, c, radius, height = set_defaults(
|
285
|
+
cell, center, where, a, b, c, radius, height
|
286
|
+
)
|
246
287
|
|
247
288
|
calc = choose_calculator(arch=arch, model_path=model, device=device)
|
248
289
|
sys.calc = calc
|
@@ -250,7 +291,8 @@ def pack_molecules(
|
|
250
291
|
e = sys.get_potential_energy() if len(sys) > 0 else 0.0
|
251
292
|
|
252
293
|
csys = sys.copy()
|
253
|
-
|
294
|
+
i = 0
|
295
|
+
while i < nmols:
|
254
296
|
accept = False
|
255
297
|
for _itry in range(ntries):
|
256
298
|
mol = load_molecule(molecule)
|
@@ -259,6 +301,11 @@ def pack_molecules(
|
|
259
301
|
mol.translate(tv)
|
260
302
|
|
261
303
|
tsys = csys.copy() + mol.copy()
|
304
|
+
if insert_strategy == "hmc":
|
305
|
+
tsys = run_md_nve(
|
306
|
+
tsys, md_temperature, md_steps, md_timestep, arch, model, device
|
307
|
+
)
|
308
|
+
|
262
309
|
tsys.calc = calc
|
263
310
|
en = tsys.get_potential_energy()
|
264
311
|
de = en - e
|
@@ -270,34 +317,55 @@ def pack_molecules(
|
|
270
317
|
if u <= acc:
|
271
318
|
accept = True
|
272
319
|
break
|
320
|
+
if every > 0 and _itry / every == 0:
|
321
|
+
csys = save_the_day(
|
322
|
+
Path(out_path) / f"{sysname}{i}{Path(molecule).stem}.cif",
|
323
|
+
device,
|
324
|
+
arch,
|
325
|
+
model,
|
326
|
+
fmax,
|
327
|
+
out_path,
|
328
|
+
md_temperature,
|
329
|
+
md_steps,
|
330
|
+
md_timestep,
|
331
|
+
relax_strategy,
|
332
|
+
)
|
273
333
|
|
274
334
|
if accept:
|
275
335
|
csys = tsys.copy()
|
276
336
|
e = en
|
277
|
-
|
278
|
-
|
337
|
+
i += 1
|
338
|
+
print(f"Inserted particle {i}")
|
339
|
+
write(Path(out_path) / f"{sysname}{i}{Path(molecule).stem}.cif", csys)
|
279
340
|
else:
|
280
341
|
# Things are bad, maybe geomatry optimisation saves us
|
342
|
+
# once you hit here is bad, this can keep looping
|
281
343
|
print(f"Failed to insert particle {i + 1} after {ntries} tries")
|
282
|
-
|
283
|
-
f"{sysname}
|
344
|
+
csys = save_the_day(
|
345
|
+
Path(out_path) / f"{sysname}{i}{Path(molecule).stem}.cif",
|
284
346
|
device,
|
285
347
|
arch,
|
286
348
|
model,
|
287
349
|
fmax,
|
288
350
|
out_path,
|
351
|
+
md_temperature,
|
352
|
+
md_steps,
|
353
|
+
md_timestep,
|
354
|
+
relax_strategy,
|
289
355
|
)
|
356
|
+
|
290
357
|
energy_final = e
|
291
358
|
|
292
359
|
# Perform final geometry optimization if requested
|
293
360
|
if geometry:
|
294
361
|
energy_final = optimize_geometry(
|
295
|
-
f"{sysname}
|
362
|
+
Path(out_path) / f"{sysname}{nmols}{Path(molecule).stem}.cif",
|
296
363
|
device,
|
297
364
|
arch,
|
298
365
|
model,
|
299
366
|
fmax,
|
300
367
|
out_path,
|
368
|
+
True,
|
301
369
|
)
|
302
370
|
return energy_final
|
303
371
|
|
@@ -329,7 +397,6 @@ def get_insertion_position(
|
|
329
397
|
if where in ["cylinderZ", "cylinderY", "cylinderX"]:
|
330
398
|
axis = where[-1].lower()
|
331
399
|
return random_point_in_cylinder(center, radius, height, axis)
|
332
|
-
# now is anywhere
|
333
400
|
return random.random(3) * [a, b, c]
|
334
401
|
|
335
402
|
|
@@ -342,6 +409,72 @@ def rotate_molecule(mol):
|
|
342
409
|
return mol
|
343
410
|
|
344
411
|
|
412
|
+
def save_the_day(
|
413
|
+
struct_path: str = "",
|
414
|
+
device: str = "",
|
415
|
+
arch: str = "",
|
416
|
+
model: str = "",
|
417
|
+
fmax: float = 0.01,
|
418
|
+
out_path: str = ".",
|
419
|
+
md_temperature: float = 100.0,
|
420
|
+
md_steps: int = 10,
|
421
|
+
md_timestep: float = 1.0,
|
422
|
+
relax_strategy: str = "geometry_optimisation",
|
423
|
+
) -> Atoms:
|
424
|
+
"""Geometry optimisation or MD to get a better structure."""
|
425
|
+
if relax_strategy == "geometry_optimisation":
|
426
|
+
_ = optimize_geometry(
|
427
|
+
struct_path,
|
428
|
+
device,
|
429
|
+
arch,
|
430
|
+
model,
|
431
|
+
fmax,
|
432
|
+
out_path,
|
433
|
+
)
|
434
|
+
return read(Path(out_path) / f"{Path(struct_path).stem}-opt.cif")
|
435
|
+
if relax_strategy == "md":
|
436
|
+
return run_md_nve(
|
437
|
+
struct_path, md_temperature, md_steps, md_timestep, arch, model, device
|
438
|
+
)
|
439
|
+
return None
|
440
|
+
|
441
|
+
|
442
|
+
def run_md_nve(
|
443
|
+
struct_path: str | Atoms,
|
444
|
+
temp: float = 100.0,
|
445
|
+
steps: int = 10,
|
446
|
+
timestep: float = 1.0,
|
447
|
+
arch: str = "",
|
448
|
+
model: str = "",
|
449
|
+
device: str = "",
|
450
|
+
) -> Atoms:
|
451
|
+
"""Run nve simulation."""
|
452
|
+
if isinstance(struct_path, Atoms):
|
453
|
+
md = NVE(
|
454
|
+
struct=struct_path,
|
455
|
+
temp=temp,
|
456
|
+
device=device,
|
457
|
+
arch=arch,
|
458
|
+
calc_kwargs={"model_paths": model},
|
459
|
+
stats_every=1,
|
460
|
+
steps=steps,
|
461
|
+
timestep=timestep,
|
462
|
+
)
|
463
|
+
else:
|
464
|
+
md = NVE(
|
465
|
+
struct_path=struct_path,
|
466
|
+
temp=temp,
|
467
|
+
device=device,
|
468
|
+
arch=arch,
|
469
|
+
calc_kwargs={"model_paths": model},
|
470
|
+
stats_every=1,
|
471
|
+
steps=steps,
|
472
|
+
timestep=timestep,
|
473
|
+
)
|
474
|
+
md.run()
|
475
|
+
return md.struct
|
476
|
+
|
477
|
+
|
345
478
|
def optimize_geometry(
|
346
479
|
struct_path: str,
|
347
480
|
device: str,
|
@@ -349,14 +482,16 @@ def optimize_geometry(
|
|
349
482
|
model: str,
|
350
483
|
fmax: float,
|
351
484
|
out_path: str = ".",
|
485
|
+
opt_cell: bool = False,
|
352
486
|
) -> float:
|
353
487
|
"""Optimize the geometry of a structure."""
|
354
488
|
geo = GeomOpt(
|
355
489
|
struct_path=struct_path,
|
356
490
|
device=device,
|
491
|
+
arch=arch,
|
357
492
|
fmax=fmax,
|
358
493
|
calc_kwargs={"model_paths": model},
|
359
|
-
filter_kwargs={"hydrostatic_strain":
|
494
|
+
filter_kwargs={"hydrostatic_strain": opt_cell},
|
360
495
|
)
|
361
496
|
geo.run()
|
362
497
|
write(Path(out_path) / f"{Path(struct_path).stem}-opt.cif", geo.struct)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: pack-mm
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.22
|
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
|
@@ -42,7 +42,7 @@ It provides both a cli and a python api, with some examples below.
|
|
42
42
|
uv pip install pack-mm
|
43
43
|
|
44
44
|
```
|
45
|
-
or install the
|
45
|
+
or install the latest
|
46
46
|
|
47
47
|
```bash
|
48
48
|
|
@@ -125,7 +125,7 @@ packmm --system Pd-super.cif --molecule H2 --nmols 50 --where anywhere --mode
|
|
125
125
|
|
126
126
|
before optimisation
|
127
127
|
|
128
|
-

|
129
129
|
|
130
130
|
|
131
131
|
after optimisation
|
@@ -0,0 +1,8 @@
|
|
1
|
+
pack_mm-0.0.22.dist-info/METADATA,sha256=5XjBJexb_jY1kVAZdZSXFcXfdWvfHJFpnsYJ25tTQlc,13509
|
2
|
+
pack_mm-0.0.22.dist-info/WHEEL,sha256=thaaA2w1JzcGC48WYufAs8nrYZjJm8LqNfnXFOFyCC4,90
|
3
|
+
pack_mm-0.0.22.dist-info/entry_points.txt,sha256=ajKA2oehIa_LCVCP2XTRxV0VNgjGl9c2wYkwk0BasrQ,66
|
4
|
+
pack_mm-0.0.22.dist-info/licenses/LICENSE,sha256=ZOYkPdn_vQ8wYJqZnjesow79F_grMbVlHcJ9V91G1pE,1100
|
5
|
+
pack_mm/__init__.py,sha256=ct7qfCmTDwhLYip6JKYWRLasmmaGYt0ColbK0CpvYZk,150
|
6
|
+
pack_mm/cli/packmm.py,sha256=E63MmBrxvn9g5GQMK5vlyq6CmHL8hgQ8CICeX2N9z1E,6398
|
7
|
+
pack_mm/core/core.py,sha256=R0d-FTmuTj-5BSwG5S4Fa6f3BFdYrvBUsV2cSwcHi2c,15269
|
8
|
+
pack_mm-0.0.22.dist-info/RECORD,,
|
pack_mm-0.0.21.dist-info/RECORD
DELETED
@@ -1,8 +0,0 @@
|
|
1
|
-
pack_mm-0.0.21.dist-info/METADATA,sha256=jW4IZ3HFn-e7AxJ8dAteajsDSs1dsybX3G9l080Gr5Y,13506
|
2
|
-
pack_mm-0.0.21.dist-info/WHEEL,sha256=thaaA2w1JzcGC48WYufAs8nrYZjJm8LqNfnXFOFyCC4,90
|
3
|
-
pack_mm-0.0.21.dist-info/entry_points.txt,sha256=ajKA2oehIa_LCVCP2XTRxV0VNgjGl9c2wYkwk0BasrQ,66
|
4
|
-
pack_mm-0.0.21.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=vNMQOVDIXyRCUWosww9sSHUxwqbjPRk5JLsb9muwpVA,11369
|
8
|
-
pack_mm-0.0.21.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|