Skip to content

Commit 80cae6d

Browse files
committed
bug: fixed #204
Now mirror does the correct thing with xy/=ab. Also enabled mirroring about user-defined vectors. Probably not so useful, but in some cases perhaps? Signed-off-by: Nick Papior <[email protected]>
1 parent 18d6f4f commit 80cae6d

File tree

2 files changed

+49
-17
lines changed

2 files changed

+49
-17
lines changed

sisl/geometry.py

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
from . import _plot as plt
1414
from . import _array as _a
15-
from ._math_small import is_ascending
15+
from ._math_small import is_ascending, cross3
1616
from ._indices import indices_in_sphere_with_dist, indices_le, indices_gt_le
1717
from ._indices import list_index_le
1818
from .messages import info, warn, SislError
@@ -2450,31 +2450,57 @@ def reverse(self, atom=None):
24502450
xyz[atom, :] = self.xyz[atom[::-1], :]
24512451
return self.__class__(xyz, atom=self.atoms.reverse(atom), sc=self.sc.copy())
24522452

2453-
def mirror(self, plane, atom=None):
2454-
""" Mirrors the atomic coordinates by multiplying by -1
2453+
def mirror(self, method, atom=None):
2454+
r""" Mirrors the atomic coordinates about the plane
24552455
24562456
This will typically move the atomic coordinates outside of the unit-cell.
24572457
This method should be used with care.
24582458
24592459
Parameters
24602460
----------
2461-
plane : {'xy'/'ab', 'yz'/'bc', 'xz'/'ac'}
2462-
mirror the structure across the lattice vector plane
2461+
method : {'xy'/'z', ..., 'ab', ..., v}
2462+
mirror the structure about a Cartesian direction (``x``, ``y``, ``z``),
2463+
plane (``xy``, ``xz``, ``yz``) or about user defined vectors (``v``).
2464+
A vector may also be specified by ``'ab'`` which is the vector normal
2465+
to the plane spanned by the first and second lattice vector.
2466+
or user defined vector (`v`)
24632467
atom : array_like, optional
24642468
only mirror a subset of atoms
24652469
"""
2466-
if not atom is None:
2467-
atom = self._sanitize_atom(atom)
2468-
else:
2470+
if atom is None:
24692471
atom = slice(None)
2472+
else:
2473+
atom = self._sanitize_atom(atom)
2474+
24702475
g = self.copy()
2471-
lplane = ''.join(sorted(plane.lower()))
2472-
if lplane in ['xy', 'ab']:
2473-
g.xyz[atom, 2] *= -1
2474-
elif lplane in ['yz', 'bc']:
2475-
g.xyz[atom, 0] *= -1
2476-
elif lplane in ['xz', 'ac']:
2477-
g.xyz[atom, 1] *= -1
2476+
if isinstance(method, str):
2477+
method = ''.join(sorted(method.lower()))
2478+
if method in ['z', 'xy']:
2479+
g.xyz[atom, 2] *= -1
2480+
elif method in ['x', 'yz']:
2481+
g.xyz[atom, 0] *= -1
2482+
elif method in ['y', 'xz']:
2483+
g.xyz[atom, 1] *= -1
2484+
elif method == 'ab':
2485+
method = cross3(self.cell[0], self.cell[1])
2486+
elif method == 'ac':
2487+
method = cross3(self.cell[0], self.cell[2])
2488+
elif method == 'bc':
2489+
method = cross3(self.cell[1], self.cell[2])
2490+
2491+
if not isinstance(method, str):
2492+
# it has to be an array of length 3
2493+
# Mirror about a user defined vector
2494+
method = _a.asarrayd(method).copy()
2495+
method /= fnorm(method)
2496+
2497+
# project onto vector
2498+
vp = self.xyz[atom, :].dot(method) * 2
2499+
2500+
# convert coordinates
2501+
# first subtract the projection, then its mirror position
2502+
self.xyz[atom, :] -= vp.reshape(-1, 1) * method.reshape(1, 3)
2503+
24782504
return self.__class__(g.xyz, atom=g.atom, sc=self.sc.copy())
24792505

24802506
@property

sisl/tests/test_geometry.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1167,8 +1167,14 @@ def test_attach1(self, setup):
11671167
g = setup.g.attach(0, setup.mol, 0, dist=[0, 0, 1.42])
11681168

11691169
def test_mirror1(self, setup):
1170-
for plane in ['xy', 'xz', 'yz']:
1171-
setup.g.mirror(plane)
1170+
g = setup.g
1171+
for plane in ['xy', 'xz', 'yz', 'ab', 'bc', 'ac']:
1172+
g.mirror(plane)
1173+
1174+
assert g.mirror('xy') == g.mirror('z')
1175+
assert g.mirror('xy') == g.mirror([0, 0, 1])
1176+
1177+
assert g.mirror('xy', [0]) == g.mirror([0, 0, 1], [0])
11721178

11731179
def test_pickle(self, setup):
11741180
import pickle as p

0 commit comments

Comments
 (0)