WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit a44e1d0

Browse files
authored
Merge pull request #230 from pyiron/unfoldprism
Remove UnfoldPrism
2 parents 0246439 + fb89577 commit a44e1d0

File tree

3 files changed

+154
-191
lines changed

3 files changed

+154
-191
lines changed

.ci_support/environment-old.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ dependencies:
66
- numpy =1.23.5
77
- mpi4py =3.1.4
88
- executorlib =0.0.1
9-
- ase =3.20.1
9+
- ase =3.23.0
1010
- scipy =1.9.3

pylammpsmpi/wrapper/ase.py

Lines changed: 27 additions & 177 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import decimal as dec
21
import importlib
32
import os
43
import warnings
@@ -29,6 +28,7 @@ def __init__(
2928
self._cores = cores
3029
if library is not None:
3130
self._interactive_library = library
31+
self._cores = library.cores
3232
elif self._cores == 1:
3333
lammps = getattr(importlib.import_module("lammps"), "lammps")
3434
if diable_log_file:
@@ -58,14 +58,13 @@ def interactive_positions_getter(self):
5858
np.array(self._interactive_library.gather_atoms("x", 1, 3)),
5959
(len(self._structure), 3),
6060
)
61-
if _check_ortho_prism(prism=self._prism):
62-
positions = np.matmul(positions, self._prism.R.T)
61+
if not _check_ortho_prism(prism=self._prism):
62+
positions = self._prism.vector_to_ase(positions)
6363
return positions
6464

6565
def interactive_positions_setter(self, positions):
66-
if _check_ortho_prism(prism=self._prism):
67-
positions = np.array(positions).reshape(-1, 3)
68-
positions = np.matmul(positions, self._prism.R)
66+
if not _check_ortho_prism(prism=self._prism):
67+
positions = self._prism.vector_to_lammps(positions)
6968
positions = np.array(positions).flatten()
7069
if self._cores == 1:
7170
self._interactive_library.scatter_atoms(
@@ -91,12 +90,12 @@ def interactive_cells_getter(self):
9190
],
9291
]
9392
)
94-
return self._prism.unfold_cell(cc)
93+
return self._prism.vector_to_ase(cc)
9594

9695
def interactive_cells_setter(self, cell):
97-
self._prism = UnfoldingPrism(cell)
96+
self._prism = Prism(cell)
9897
lx, ly, lz, xy, xz, yz = self._prism.get_lammps_prism()
99-
if _check_ortho_prism(prism=self._prism):
98+
if not _check_ortho_prism(prism=self._prism):
10099
warnings.warn(
101100
"Warning: setting upper trangular matrix might slow down the calculation"
102101
)
@@ -131,8 +130,8 @@ def interactive_forces_getter(self):
131130
np.array(self._interactive_library.gather_atoms("f", 1, 3)),
132131
(len(self._structure), 3),
133132
)
134-
if _check_ortho_prism(prism=self._prism):
135-
ff = np.matmul(ff, self._prism.R.T)
133+
if not _check_ortho_prism(prism=self._prism):
134+
ff = self._prism.vector_to_ase(ff)
136135
return ff
137136

138137
def interactive_structure_setter(
@@ -153,8 +152,8 @@ def interactive_structure_setter(
153152
self.interactive_lib_command(command="atom_style " + atom_style)
154153

155154
self.interactive_lib_command(command="atom_modify map array")
156-
self._prism = UnfoldingPrism(structure.cell)
157-
if _check_ortho_prism(prism=self._prism):
155+
self._prism = Prism(structure.cell)
156+
if not _check_ortho_prism(prism=self._prism):
158157
warnings.warn(
159158
"Warning: setting upper trangular matrix might slow down the calculation"
160159
)
@@ -214,11 +213,10 @@ def interactive_structure_setter(
214213
self.interactive_lib_command(
215214
command="mass {0:3d} {1:f}".format(id_eam + 1, 1.00),
216215
)
217-
positions = structure.positions.flatten()
218-
if _check_ortho_prism(prism=self._prism):
219-
positions = np.array(positions).reshape(-1, 3)
220-
positions = np.matmul(positions, self._prism.R)
221-
positions = positions.flatten()
216+
if not _check_ortho_prism(prism=self._prism):
217+
positions = self._prism.vector_to_lammps(structure.positions).flatten()
218+
else:
219+
positions = structure.positions.flatten()
222220
try:
223221
elem_all = get_lammps_indicies_from_ase_structure(
224222
structure=structure, el_eam_lst=el_eam_lst
@@ -242,7 +240,7 @@ def interactive_structure_setter(
242240
else:
243241
self._interactive_library.create_atoms(
244242
n=len(structure),
245-
id=None,
243+
id=range(1, len(structure) + 1),
246244
type=elem_all,
247245
x=positions,
248246
v=None,
@@ -289,9 +287,8 @@ def interactive_pressures_getter(self):
289287
],
290288
]
291289
)
292-
if _check_ortho_prism(prism=self._prism):
293-
rotation_matrix = self._prism.R.T
294-
pp = rotation_matrix.T @ pp @ rotation_matrix
290+
if not _check_ortho_prism(prism=self._prism):
291+
pp = self._prism.tensor2_to_ase(pp)
295292
return pp
296293

297294
def interactive_indices_setter(self, indices, el_eam_lst):
@@ -316,7 +313,7 @@ def interactive_stress_getter(self, enable_stress_computation=True):
316313
if enable_stress_computation:
317314
self.interactive_lib_command("compute st all stress/atom NULL")
318315
self.interactive_lib_command("run 0")
319-
id_lst = self._interactive_library.extract_atom("id", 0)
316+
id_lst = self._interactive_library.extract_atom("id")
320317
id_lst = np.array([id_lst[i] for i in range(len(self._structure))]) - 1
321318
id_lst = np.arange(len(id_lst))[np.argsort(id_lst)]
322319
ind = np.array([0, 3, 4, 3, 1, 5, 4, 5, 2])
@@ -330,18 +327,18 @@ def interactive_stress_getter(self, enable_stress_computation=True):
330327
* constants.bar
331328
* constants.angstrom**3
332329
)
333-
if _check_ortho_prism(prism=self._prism):
334-
ss = np.einsum("ij,njk->nik", self._prism.R, ss)
335-
ss = np.einsum("nij,kj->nik", ss, self._prism.R)
330+
if not _check_ortho_prism(prism=self._prism):
331+
ss = np.einsum("ij,njk->nik", self._prism.rot_mat, ss)
332+
ss = np.einsum("nij,kj->nik", ss, self._prism.rot_mat)
336333
return ss
337334

338335
def interactive_velocities_getter(self):
339336
velocity = np.reshape(
340337
np.array(self._interactive_library.gather_atoms("v", 1, 3)),
341338
(len(self._structure), 3),
342339
)
343-
if _check_ortho_prism(prism=self._prism):
344-
velocity = np.matmul(velocity, self._prism.R.T)
340+
if not _check_ortho_prism(prism=self._prism):
341+
velocity = self._prism.vector_to_ase(velocity)
345342
return velocity
346343

347344
def close(self):
@@ -366,153 +363,6 @@ def __exit__(self, exc_type, exc_val, exc_tb):
366363
self.close()
367364

368365

369-
class UnfoldingPrism(Prism):
370-
"""
371-
Create a lammps-style triclinic prism object from a cell
372-
373-
The main purpose of the prism-object is to create suitable
374-
string representations of prism limits and atom positions
375-
within the prism.
376-
When creating the object, the digits parameter (default set to 10)
377-
specify the precision to use.
378-
lammps is picky about stuff being within semi-open intervals,
379-
e.g. for atom positions (when using create_atom in the in-file),
380-
x must be within [xlo, xhi).
381-
382-
Args:
383-
cell:
384-
pbc:
385-
digits:
386-
"""
387-
388-
def __init__(self, cell, pbc=(True, True, True), digits=10):
389-
# Temporary fix. Since the arguments for the constructor have changed, try to see if it is compatible with
390-
# the latest ase. If not, revert to the old __init__ parameters.
391-
try:
392-
super(UnfoldingPrism, self).__init__(
393-
cell, pbc=pbc, tolerance=float("1e-{}".format(digits))
394-
)
395-
except TypeError:
396-
super(UnfoldingPrism, self).__init__(cell, pbc=pbc, digits=digits)
397-
a, b, c = cell
398-
an, bn, cn = [np.linalg.norm(v) for v in cell]
399-
400-
alpha = np.arccos(np.dot(b, c) / (bn * cn))
401-
beta = np.arccos(np.dot(a, c) / (an * cn))
402-
gamma = np.arccos(np.dot(a, b) / (an * bn))
403-
404-
xhi = an
405-
xyp = np.cos(gamma) * bn
406-
yhi = np.sin(gamma) * bn
407-
xzp = np.cos(beta) * cn
408-
yzp = (bn * cn * np.cos(alpha) - xyp * xzp) / yhi
409-
zhi = np.sqrt(cn**2 - xzp**2 - yzp**2)
410-
411-
# Set precision
412-
self.car_prec = dec.Decimal("10.0") ** int(
413-
np.floor(np.log10(max((xhi, yhi, zhi)))) - digits
414-
)
415-
self.dir_prec = dec.Decimal("10.0") ** (-digits)
416-
self.acc = float(self.car_prec)
417-
self.eps = np.finfo(xhi).eps
418-
419-
# For rotating positions from ase to lammps
420-
apre = np.array(((xhi, 0, 0), (xyp, yhi, 0), (xzp, yzp, zhi)))
421-
# np.linalg.inv(cell) ?= np.array([np.cross(b, c), np.cross(c, a), np.cross(a, b)]).T / np.linalg.det(cell)
422-
self.R = np.dot(np.linalg.inv(cell), apre)
423-
424-
def fold(vec, pvec, i):
425-
p = pvec[i]
426-
x = vec[i] + 0.5 * p
427-
n = (np.mod(x, p) - x) / p
428-
return [float(self.f2qdec(vec_a)) for vec_a in (vec + n * pvec)], n
429-
430-
apre[1, :], n1 = fold(apre[1, :], apre[0, :], 0)
431-
if np.abs(apre[1, 0] / apre[0, 0]) > 0.5:
432-
apre[1, 0] -= np.sign(n1) * apre[0, 0]
433-
n1 -= np.sign(n1)
434-
435-
apre[2, :], n2 = fold(apre[2, :], apre[1, :], 1)
436-
if np.abs(apre[2, 1] / apre[1, 1]) > 0.5:
437-
apre[2, 1] -= np.sign(n2) * apre[1, 1]
438-
n2 -= np.sign(n2)
439-
440-
apre[2, :], n3 = fold(apre[2, :], apre[0, :], 0)
441-
if np.abs(apre[2, 0] / apre[0, 0]) > 0.5:
442-
apre[2, 0] -= np.sign(n3) * apre[0, 0]
443-
n3 -= np.sign(n3)
444-
self.ns = [n1, n2, n3]
445-
446-
d_a = apre[0, 0] / 2 - apre[1, 0]
447-
if np.abs(d_a) < self.acc:
448-
if d_a < 0:
449-
print("debug: apply shift")
450-
apre[1, 0] += 2 * d_a
451-
apre[2, 0] += 2 * d_a
452-
453-
self.A = apre
454-
455-
if self.is_skewed() and (not (pbc[0] and pbc[1] and pbc[2])):
456-
warnings.warn(
457-
"Skewed lammps cells should have PBC == True in all directions!"
458-
)
459-
460-
def unfold_cell(self, cell):
461-
"""
462-
Unfold LAMMPS cell to original
463-
464-
Let C be the pyiron_atomistics cell and A be the Lammps cell, then define (in init) the rotation matrix between them as
465-
R := C^inv.A
466-
And recall that rotation matrices have the property
467-
R^T == R^inv
468-
Then left multiply the definition of R by C, and right multiply by R.T to get
469-
C.R.R^T = C.C^inv.A.R^T
470-
Then
471-
C = A.R^T
472-
473-
After that, account for the folding process.
474-
475-
Args:
476-
cell: LAMMPS cell,
477-
478-
Returns:
479-
unfolded cell
480-
"""
481-
# Rotation
482-
ucell = np.dot(cell, self.R.T)
483-
# Folding
484-
a = ucell[0]
485-
bp = ucell[1]
486-
cpp = ucell[2]
487-
(n1, n2, n3) = self.ns
488-
b = bp - n1 * a
489-
c = cpp - n2 * bp - n3 * a
490-
return np.array([a, b, c])
491-
492-
def pos_to_lammps(self, position):
493-
"""
494-
Rotate an ase-cell position to the lammps cell orientation
495-
496-
Args:
497-
position:
498-
499-
Returns:
500-
tuple of float.
501-
"""
502-
return tuple([x for x in np.dot(position, self.R)])
503-
504-
def f2qdec(self, f):
505-
return dec.Decimal(repr(f)).quantize(self.car_prec, dec.ROUND_DOWN)
506-
507-
def f2s(self, f):
508-
return str(dec.Decimal(repr(f)).quantize(self.car_prec, dec.ROUND_HALF_EVEN))
509-
510-
def get_lammps_prism_str(self):
511-
"""Return a tuple of strings"""
512-
p = self.get_lammps_prism()
513-
return tuple([self.f2s(x) for x in p])
514-
515-
516366
def cell_is_skewed(cell, tolerance=1.0e-8):
517367
"""
518368
Check whether the simulation box is skewed/sheared. The algorithm compares the box volume
@@ -538,14 +388,14 @@ def _check_ortho_prism(prism, rtol=0.0, atol=1e-08):
538388
Check if the rotation matrix of the UnfoldingPrism object is sufficiently close to a unit matrix
539389
540390
Args:
541-
prism (pyiron_atomistics.lammps.structure.UnfoldingPrism): UnfoldingPrism object to check
391+
prism (ase.calculators.lammps.Prism): Prism object to check
542392
rtol (float): relative precision for numpy.isclose()
543393
atol (float): absolute precision for numpy.isclose()
544394
545395
Returns:
546396
boolean: True or False
547397
"""
548-
return np.isclose(prism.R, np.eye(3), rtol=rtol, atol=atol).all()
398+
return np.isclose(prism.rot_mat, np.eye(3), rtol=rtol, atol=atol).all()
549399

550400

551401
def get_species_symbols(structure):

0 commit comments

Comments
 (0)