ipyvasp 0.9.7__tar.gz → 0.9.81__tar.gz
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.
- {ipyvasp-0.9.7 → ipyvasp-0.9.81}/PKG-INFO +1 -1
- {ipyvasp-0.9.7 → ipyvasp-0.9.81}/ipyvasp/_lattice.py +62 -43
- ipyvasp-0.9.81/ipyvasp/_version.py +1 -0
- {ipyvasp-0.9.7 → ipyvasp-0.9.81}/ipyvasp/core/parser.py +4 -1
- {ipyvasp-0.9.7 → ipyvasp-0.9.81}/ipyvasp/core/serializer.py +20 -8
- {ipyvasp-0.9.7 → ipyvasp-0.9.81}/ipyvasp/lattice.py +12 -12
- {ipyvasp-0.9.7 → ipyvasp-0.9.81}/ipyvasp/widgets.py +1 -1
- {ipyvasp-0.9.7 → ipyvasp-0.9.81}/ipyvasp.egg-info/PKG-INFO +1 -1
- ipyvasp-0.9.7/ipyvasp/_version.py +0 -1
- {ipyvasp-0.9.7 → ipyvasp-0.9.81}/LICENSE +0 -0
- {ipyvasp-0.9.7 → ipyvasp-0.9.81}/README.md +0 -0
- {ipyvasp-0.9.7 → ipyvasp-0.9.81}/ipyvasp/__init__.py +0 -0
- {ipyvasp-0.9.7 → ipyvasp-0.9.81}/ipyvasp/__main__.py +0 -0
- {ipyvasp-0.9.7 → ipyvasp-0.9.81}/ipyvasp/_enplots.py +0 -0
- {ipyvasp-0.9.7 → ipyvasp-0.9.81}/ipyvasp/bsdos.py +0 -0
- {ipyvasp-0.9.7 → ipyvasp-0.9.81}/ipyvasp/cli.py +0 -0
- {ipyvasp-0.9.7 → ipyvasp-0.9.81}/ipyvasp/core/__init__.py +0 -0
- {ipyvasp-0.9.7 → ipyvasp-0.9.81}/ipyvasp/core/plot_toolkit.py +0 -0
- {ipyvasp-0.9.7 → ipyvasp-0.9.81}/ipyvasp/core/spatial_toolkit.py +0 -0
- {ipyvasp-0.9.7 → ipyvasp-0.9.81}/ipyvasp/evals_dataframe.py +0 -0
- {ipyvasp-0.9.7 → ipyvasp-0.9.81}/ipyvasp/misc.py +0 -0
- {ipyvasp-0.9.7 → ipyvasp-0.9.81}/ipyvasp/potential.py +0 -0
- {ipyvasp-0.9.7 → ipyvasp-0.9.81}/ipyvasp/utils.py +0 -0
- {ipyvasp-0.9.7 → ipyvasp-0.9.81}/ipyvasp.egg-info/SOURCES.txt +0 -0
- {ipyvasp-0.9.7 → ipyvasp-0.9.81}/ipyvasp.egg-info/dependency_links.txt +0 -0
- {ipyvasp-0.9.7 → ipyvasp-0.9.81}/ipyvasp.egg-info/entry_points.txt +0 -0
- {ipyvasp-0.9.7 → ipyvasp-0.9.81}/ipyvasp.egg-info/requires.txt +0 -0
- {ipyvasp-0.9.7 → ipyvasp-0.9.81}/ipyvasp.egg-info/top_level.txt +0 -0
- {ipyvasp-0.9.7 → ipyvasp-0.9.81}/setup.cfg +0 -0
- {ipyvasp-0.9.7 → ipyvasp-0.9.81}/setup.py +0 -0
|
@@ -6,6 +6,7 @@ import requests as req
|
|
|
6
6
|
import inspect
|
|
7
7
|
from itertools import combinations, product
|
|
8
8
|
from functools import lru_cache
|
|
9
|
+
from typing import NamedTuple
|
|
9
10
|
|
|
10
11
|
from scipy.spatial import ConvexHull, KDTree
|
|
11
12
|
import plotly.graph_objects as go
|
|
@@ -238,7 +239,7 @@ def write_poscar(poscar_data, outfile=None, selective_dynamics=None, overwrite=F
|
|
|
238
239
|
----------
|
|
239
240
|
outfile : PathLike
|
|
240
241
|
selective_dynamics : callable
|
|
241
|
-
If given, should be a function like `f(
|
|
242
|
+
If given, should be a function like `f(a) -> (a.p < 1/4)` or `f(a) -> (a.x < 1/4, a.y < 1/4, a.z < 1/4)`
|
|
242
243
|
which turns on/off selective dynamics for each atom based in each dimension.
|
|
243
244
|
See `ipyvasp.POSCAR.data.get_selective_dynamics` for more info.
|
|
244
245
|
overwrite: bool
|
|
@@ -1192,8 +1193,11 @@ def splot_kpath(
|
|
|
1192
1193
|
labels = [
|
|
1193
1194
|
"[{0:5.2f}, {1:5.2f}, {2:5.2f}]".format(x, y, z) for x, y, z in kpoints
|
|
1194
1195
|
]
|
|
1196
|
+
|
|
1197
|
+
if fmt_label is None:
|
|
1198
|
+
fmt_label = lambda x: (x, {"color": "blue"})
|
|
1195
1199
|
|
|
1196
|
-
_validate_label_func(fmt_label,
|
|
1200
|
+
_validate_label_func(fmt_label,labels[0])
|
|
1197
1201
|
|
|
1198
1202
|
coords = bz_data.to_cartesian(kpoints)
|
|
1199
1203
|
if _zoffset and plane:
|
|
@@ -1565,25 +1569,50 @@ def _get_bond_length(poscar_data, bond_length=None):
|
|
|
1565
1569
|
) # Add 5% margin over mean distance, this covers same species too, and in multiple species, this will stop bonding between same species.
|
|
1566
1570
|
|
|
1567
1571
|
|
|
1568
|
-
|
|
1569
|
-
"
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
+
class _Atom(NamedTuple):
|
|
1573
|
+
"Object passed to POSCAR operations `func` where atomic sites are modified. Additinal property p -> array([x,y,z])."
|
|
1574
|
+
symbol : str
|
|
1575
|
+
number : int
|
|
1576
|
+
index : int
|
|
1577
|
+
x : float
|
|
1578
|
+
y : float
|
|
1579
|
+
z : float
|
|
1572
1580
|
|
|
1573
|
-
|
|
1581
|
+
@property
|
|
1582
|
+
def p(self): return np.array([self.x,self.y,self.z]) # for robust operations
|
|
1583
|
+
|
|
1584
|
+
class _AtomLabel(str):
|
|
1585
|
+
"Object passed to `fmt_label` in plotting. `number` and `symbol` are additional attributes and `to_latex` is a method."
|
|
1586
|
+
@property
|
|
1587
|
+
def number(self): return int(self.split()[1])
|
|
1588
|
+
@property
|
|
1589
|
+
def symbol(self): return self.split()[0]
|
|
1590
|
+
def to_latex(self): return "{}$_{{{}}}$".format(*self.split())
|
|
1591
|
+
|
|
1592
|
+
def _validate_func(func):
|
|
1593
|
+
if not callable(func):
|
|
1594
|
+
raise ValueError("`func` must be a callable function with single parameter `Atom(symbol,number, index,x,y,z)`.")
|
|
1595
|
+
|
|
1596
|
+
if len(inspect.signature(func).parameters) != 1:
|
|
1574
1597
|
raise ValueError(
|
|
1575
|
-
"`func` takes exactly
|
|
1598
|
+
"`func` takes exactly 1 argument: `Atom(symbol, number, index,x,y,z)` in fractional coordinates"
|
|
1599
|
+
)
|
|
1600
|
+
|
|
1601
|
+
ret = func(_Atom('',0,0,0,0,0))
|
|
1602
|
+
if not isinstance(ret, (bool, np.bool_)):
|
|
1603
|
+
raise ValueError(
|
|
1604
|
+
f"`func` must be a function that returns a bool, got {type(ret)}."
|
|
1576
1605
|
)
|
|
1577
1606
|
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1607
|
+
def _masked_data(poscar_data, func):
|
|
1608
|
+
"Returns indices of sites which satisfy the func."
|
|
1609
|
+
_validate_func(func)
|
|
1581
1610
|
eqv_inds = tuple(getattr(poscar_data.metadata, "eqv_indices",[]))
|
|
1582
1611
|
|
|
1583
1612
|
pick = []
|
|
1584
1613
|
for i, pos in enumerate(poscar_data.positions):
|
|
1585
1614
|
idx = eqv_inds[i] if eqv_inds else i # map to original index
|
|
1586
|
-
if func(idx, *pos):
|
|
1615
|
+
if func(_Atom(*poscar_data._sn[i], idx, *pos)): # labels based on i, not eqv_idx
|
|
1587
1616
|
pick.append(i)
|
|
1588
1617
|
return pick # could be duplicate indices
|
|
1589
1618
|
|
|
@@ -1604,11 +1633,14 @@ def _filter_pairs(labels, pairs, dist, bond_length):
|
|
|
1604
1633
|
# Return all pairs otherwise
|
|
1605
1634
|
return pairs # None -> auto calculate bond_length, number -> use that number
|
|
1606
1635
|
|
|
1607
|
-
def
|
|
1608
|
-
"""Filter sites based on a function that acts on
|
|
1636
|
+
def filter_atoms(poscar_data, func, tol = 0.01):
|
|
1637
|
+
"""Filter atomic sites based on a function that acts on an atom such as `lambda a: (a.p < 1/2).all()`.
|
|
1638
|
+
`atom` passed to function is a namedtuple like `Atom(symbol,number,index,x,y,z)` which has extra attribute `p = array([x,y,z])`.
|
|
1609
1639
|
This may include equivalent sites, so it should be used for plotting purpose only, e.g. showing atoms on a plane.
|
|
1610
1640
|
An attribute `source_indices` is added to metadata which is useful to pick other things such as `OUTCAR.ion_pot[POSCAR.filter(...).data.metadata.source_indices]`.
|
|
1611
1641
|
|
|
1642
|
+
>>> filter_atoms(..., lambda a: a.symbol=='Ga' or a.number in range(2)) # picks all Ga atoms and first two atoms of every other types.
|
|
1643
|
+
|
|
1612
1644
|
Note: If you are filtering a plane with more than one non-zero hkl like 110, you may first need to translate or set boundary on POSCAR to bring desired plane in full view to include all atoms.
|
|
1613
1645
|
"""
|
|
1614
1646
|
if hasattr(poscar_data.metadata, 'source_indices'):
|
|
@@ -1804,13 +1836,13 @@ def iplot_lattice(
|
|
|
1804
1836
|
return fig
|
|
1805
1837
|
|
|
1806
1838
|
|
|
1807
|
-
def _validate_label_func(fmt_label,
|
|
1839
|
+
def _validate_label_func(fmt_label,label):
|
|
1808
1840
|
if not callable(fmt_label):
|
|
1809
1841
|
raise ValueError("fmt_label must be a callable function.")
|
|
1810
1842
|
if len(inspect.signature(fmt_label).parameters.values()) != 1:
|
|
1811
|
-
raise ValueError("fmt_label must have only one argument.")
|
|
1843
|
+
raise ValueError("fmt_label must have only one argument that accepts a str like 'Ga 1'.")
|
|
1812
1844
|
|
|
1813
|
-
test_out = fmt_label(
|
|
1845
|
+
test_out = fmt_label(_AtomLabel(label))
|
|
1814
1846
|
if isinstance(test_out, (list, tuple)):
|
|
1815
1847
|
if len(test_out) != 2:
|
|
1816
1848
|
raise ValueError(
|
|
@@ -1903,7 +1935,8 @@ def splot_lattice(
|
|
|
1903
1935
|
bond_kws : dict
|
|
1904
1936
|
Keyword arguments to pass to `LineCollection`/`Line3DCollection` for plotting bonds.
|
|
1905
1937
|
fmt_label : callable
|
|
1906
|
-
If given, each site label is passed to it
|
|
1938
|
+
If given, each site label is passed to it as a subclass of str 'Ga 1' with extra attributes `symbol` and `number` and a method `to_latex`.
|
|
1939
|
+
You can show specific labels based on condition, e.g. `lambda lab: lab.to_latex() if lab.number in [1,5] else ''` will show 1st and 5th atom of each types.
|
|
1907
1940
|
It must return a string or a list/tuple of length 2 with first item as label and second item as dictionary of keywords to pass to `plt.text`.
|
|
1908
1941
|
plot_cell : bool
|
|
1909
1942
|
Default is True, plot unit cell with default settings.
|
|
@@ -1935,7 +1968,7 @@ def splot_lattice(
|
|
|
1935
1968
|
pairs = _filter_pairs(labels, pairs, dist, bond_length)
|
|
1936
1969
|
|
|
1937
1970
|
if fmt_label is not None:
|
|
1938
|
-
_validate_label_func(fmt_label,
|
|
1971
|
+
_validate_label_func(fmt_label,labels[0])
|
|
1939
1972
|
|
|
1940
1973
|
if plot_cell:
|
|
1941
1974
|
bz_data = serializer.CellData(
|
|
@@ -2002,7 +2035,7 @@ def splot_lattice(
|
|
|
2002
2035
|
)
|
|
2003
2036
|
if fmt_label:
|
|
2004
2037
|
for i, coord in enumerate(coords):
|
|
2005
|
-
lab, textkws = fmt_label(labels[i]), {}
|
|
2038
|
+
lab, textkws = fmt_label(_AtomLabel(labels[i])), {}
|
|
2006
2039
|
if isinstance(lab, (list, tuple)):
|
|
2007
2040
|
lab, textkws = lab
|
|
2008
2041
|
ax.text(*coord, lab, **textkws)
|
|
@@ -2027,7 +2060,7 @@ def splot_lattice(
|
|
|
2027
2060
|
if fmt_label:
|
|
2028
2061
|
labels = [labels[i] for i in zorder] # Reorder labels
|
|
2029
2062
|
for i, coord in enumerate(coords[zorder]):
|
|
2030
|
-
lab, textkws = fmt_label(labels[i]), {}
|
|
2063
|
+
lab, textkws = fmt_label(_AtomLabel(labels[i])), {}
|
|
2031
2064
|
if isinstance(lab, (list, tuple)):
|
|
2032
2065
|
lab, textkws = lab
|
|
2033
2066
|
ax.text(*coord[[ix, iy]], lab, **textkws)
|
|
@@ -2512,24 +2545,8 @@ def add_atoms(poscar_data, name, positions):
|
|
|
2512
2545
|
return serializer.PoscarData(data) # Return new POSCAR
|
|
2513
2546
|
|
|
2514
2547
|
|
|
2515
|
-
def _validate_func(func, nargs, return_type):
|
|
2516
|
-
if not callable(func):
|
|
2517
|
-
raise ValueError("`func` must be a callable function.")
|
|
2518
|
-
|
|
2519
|
-
if len(inspect.signature(func).parameters) != nargs:
|
|
2520
|
-
raise ValueError(
|
|
2521
|
-
f"`func` must be a function with {nargs} arguments, got {len(inspect.signature(func).parameters)}."
|
|
2522
|
-
)
|
|
2523
|
-
ret = func(*range(nargs))
|
|
2524
|
-
if not isinstance(ret, return_type):
|
|
2525
|
-
raise ValueError(
|
|
2526
|
-
f"`func` must be a function that returns {return_type}, got {type(ret)}."
|
|
2527
|
-
)
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
2548
|
def replace_atoms(poscar_data, func, name):
|
|
2531
|
-
"""Replace atoms satisfying a `func(
|
|
2532
|
-
_validate_func(func, 4, bool)
|
|
2549
|
+
"""Replace atoms satisfying a `func(atom) -> bool` with a new `name`. Like `lambda a: a.symbol == 'Ga'`"""
|
|
2533
2550
|
data = poscar_data.to_dict() # Copy data to avoid modifying original
|
|
2534
2551
|
mask = _masked_data(poscar_data, func)
|
|
2535
2552
|
new_types = {**{k: [] for k in poscar_data.types.keys()}, name: []}
|
|
@@ -2570,19 +2587,21 @@ def sort_poscar(poscar_data, new_order):
|
|
|
2570
2587
|
|
|
2571
2588
|
return serializer.PoscarData(data)
|
|
2572
2589
|
|
|
2573
|
-
|
|
2574
2590
|
def remove_atoms(poscar_data, func, fillby=None):
|
|
2575
|
-
"""Remove atoms that satisfy `func(
|
|
2591
|
+
"""Remove atoms that satisfy `func(atom) -> bool` on their fractional coordinates like `lambda a: all(a.p < 1/2)`.
|
|
2592
|
+
`atom` passed to function is a namedtuple like `Atom(symbol,number,index,x,y,z)` which has extra attribute `p = array([x,y,z])`.
|
|
2576
2593
|
If `fillby` is given, it will fill the removed atoms with atoms from fillby POSCAR.
|
|
2577
2594
|
|
|
2595
|
+
>>> remove_atoms(..., lambda a: sum((a.p - 0.5)**2) <= 0.25**2) # remove atoms in center of cell inside radius of 0.25
|
|
2596
|
+
|
|
2578
2597
|
.. note::
|
|
2579
2598
|
The coordinates of fillby POSCAR are transformed to basis of given POSCAR, before filling.
|
|
2580
2599
|
So a good filling is only guaranteed if both POSCARs have smaller lattice mismatch.
|
|
2581
2600
|
"""
|
|
2582
|
-
_validate_func(func
|
|
2601
|
+
_validate_func(func) # need to validate for fillbay
|
|
2583
2602
|
data = poscar_data.to_dict() # Copy data to avoid modifying original
|
|
2584
2603
|
positions = data["positions"]
|
|
2585
|
-
mask = _masked_data(poscar_data, lambda
|
|
2604
|
+
mask = _masked_data(poscar_data, lambda s: not func(s))
|
|
2586
2605
|
|
|
2587
2606
|
new_types = {k: [] for k in poscar_data.types.keys()}
|
|
2588
2607
|
for k, vs in data["types"].items():
|
|
@@ -2601,7 +2620,7 @@ def remove_atoms(poscar_data, func, fillby=None):
|
|
|
2601
2620
|
|
|
2602
2621
|
def keep_pos(i, x, y, z): # keep positions in basis of given data
|
|
2603
2622
|
u, v, w = to_basis(poscar_data.basis, to_R3(fillby.basis, [[x, y, z]]))[0]
|
|
2604
|
-
return bool(func(u, v, w))
|
|
2623
|
+
return bool(func(_Atom('', 0, 0, u, v, w)))
|
|
2605
2624
|
|
|
2606
2625
|
mask = _masked_data(fillby, keep_pos)
|
|
2607
2626
|
N_prev = len(data["positions"]) # before filling
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.9.81"
|
|
@@ -204,7 +204,10 @@ class Vasprun(DataSource):
|
|
|
204
204
|
else False
|
|
205
205
|
)
|
|
206
206
|
info_dict["EFERMI"] = float(
|
|
207
|
-
ET.fromstring(next(
|
|
207
|
+
ET.fromstring(next(chain(
|
|
208
|
+
self.read("<i.*efermi", "</i>"), # not always there but this is correct one
|
|
209
|
+
self.read("<i.*EFERMI", "</i>") # zero, always there in start
|
|
210
|
+
))).text
|
|
208
211
|
)
|
|
209
212
|
info_dict["NEDOS"] = int(
|
|
210
213
|
ET.fromstring(next(self.read("<i.*NEDOS", "</i>"))).text
|
|
@@ -329,6 +329,15 @@ class PoscarData(Dict2Data):
|
|
|
329
329
|
"Returns the symbols of the atoms in the poscar data without numbers"
|
|
330
330
|
return np.array([lab.split()[0] for lab in self.labels])
|
|
331
331
|
|
|
332
|
+
@property
|
|
333
|
+
def _sn(self): # symbol and number
|
|
334
|
+
return np.array([[f(v) for f,v in zip((str,int),lab.split())] for lab in self.labels],dtype=object)
|
|
335
|
+
|
|
336
|
+
@property
|
|
337
|
+
def sites(self):
|
|
338
|
+
"Returns data with types mapped to their positions."
|
|
339
|
+
return Dict2Data({k: self.positions[v] for k,v in self.types.items()})
|
|
340
|
+
|
|
332
341
|
@property
|
|
333
342
|
def G(self):
|
|
334
343
|
"""Return metric tensor to be used with fractional coordinates.
|
|
@@ -488,26 +497,29 @@ class PoscarData(Dict2Data):
|
|
|
488
497
|
"""
|
|
489
498
|
Returns a dictionary of {'Ga 1': 'T T T', 'As 1': 'T F F',...} for each atom in the poscar data.
|
|
490
499
|
|
|
491
|
-
`func` should be a callable like `
|
|
500
|
+
`func` should be a callable like `func(atom) -> (bool, bool, bool)` which turns on/off selective dynamics for each atom based in each dimension.
|
|
501
|
+
`atom` passed to function is a namedtuple like `Atom(symbol,number,index,x,y,z)` which has extra attribute `p = array([x,y,z])`.
|
|
492
502
|
|
|
493
503
|
You can visualize selective dynamics sites by their labels as follows:
|
|
494
504
|
|
|
495
505
|
|
|
496
506
|
>>> poscar = POSCAR.from_file('POSCAR')
|
|
497
|
-
>>> sd = poscar.data.get_selective_dynamics(lambda
|
|
507
|
+
>>> sd = poscar.data.get_selective_dynamics(lambda a: (True, False, True) if a.index % 2 == 0 else (False, True, False)) # Just an example
|
|
498
508
|
>>> poscar.splot_lattice(..., fmt_label = lambda lab: sd[lab]) # This will label sites as T T T, F F F, ... and so so on
|
|
499
509
|
"""
|
|
500
510
|
if not callable(func):
|
|
501
511
|
raise TypeError(
|
|
502
|
-
"`func` should be a callable
|
|
512
|
+
"`func` should be a callable with one paramter `Atom(symbol,number, index, x,y,z)`"
|
|
503
513
|
)
|
|
504
514
|
|
|
505
|
-
if len(inspect.signature(func).parameters) !=
|
|
515
|
+
if len(inspect.signature(func).parameters) != 1:
|
|
506
516
|
raise ValueError(
|
|
507
|
-
"`func` should be a callable function with
|
|
517
|
+
"`func` should be a callable function with one paramter `Atom(symbol,number, index, x,y,z)` in fractional coordinates."
|
|
508
518
|
)
|
|
519
|
+
|
|
520
|
+
from .._lattice import _Atom # avoids circular import
|
|
509
521
|
|
|
510
|
-
test_output = func(0, 0, 0, 0)
|
|
522
|
+
test_output = func(_Atom('',0, 0, 0, 0, 0))
|
|
511
523
|
if (
|
|
512
524
|
not isinstance(test_output, (list, tuple, np.ndarray))
|
|
513
525
|
or len(test_output) != 3
|
|
@@ -517,13 +529,13 @@ class PoscarData(Dict2Data):
|
|
|
517
529
|
)
|
|
518
530
|
|
|
519
531
|
for out in test_output:
|
|
520
|
-
if not isinstance(out, bool):
|
|
532
|
+
if not isinstance(out, (bool,np.bool_)):
|
|
521
533
|
raise ValueError(
|
|
522
534
|
"`func` should return boolean values in list/tuple/array like (True, False, True)"
|
|
523
535
|
)
|
|
524
536
|
|
|
525
537
|
sd_list = [
|
|
526
|
-
" ".join("T" if s else "F" for s in func(i, *p))
|
|
538
|
+
" ".join("T" if s else "F" for s in func(_Atom(*self._sn[i],i, *p)))
|
|
527
539
|
for i, p in enumerate(self.positions)
|
|
528
540
|
]
|
|
529
541
|
labels = np.array(
|
|
@@ -313,13 +313,13 @@ class POSCAR:
|
|
|
313
313
|
|
|
314
314
|
Prefrence order: data > content > path
|
|
315
315
|
|
|
316
|
-
Note:
|
|
316
|
+
Note: POSCAR operations that need a `func` accept basis, atom tuple, label etc. Read their documentation.
|
|
317
317
|
|
|
318
318
|
```python
|
|
319
319
|
pc = POSCAR()
|
|
320
|
-
pc.
|
|
321
|
-
pc.
|
|
322
|
-
pc.
|
|
320
|
+
pc.filter_atoms(lambda a: a.symbol == 'Ga') # a is namedtuple `Atom(symbol,number,index,x,y,z)` which has extra attribute `p = array([x,y,z])`.
|
|
321
|
+
pc.transform(lambda a,b,c: (a+b,a-b,c)) # basis or transform matrix
|
|
322
|
+
pc.splot_lattice(lambda lab: lab.to_latex()) # lab is str subclass like `AtomLabel('Ga 1')` with extra attributes `symbol,number, to_latex()` that can be used to show specific sites labels only.
|
|
323
323
|
```
|
|
324
324
|
|
|
325
325
|
Tip: You can use `self.auto_renderer.on()` to keep doing opertions and visualize while last line of any cell is a POSCAR object.
|
|
@@ -354,13 +354,13 @@ class POSCAR:
|
|
|
354
354
|
|
|
355
355
|
@property
|
|
356
356
|
def last(self):
|
|
357
|
-
"""Points to last created POSCAR instance during chained operations!
|
|
357
|
+
"""Points to last created POSCAR instance during chained operations! You don't need to store results
|
|
358
358
|
|
|
359
359
|
```python
|
|
360
360
|
pc = POSCAR()
|
|
361
|
-
pc.
|
|
362
|
-
pc.set_boundary([-2,2]).
|
|
363
|
-
pc.set_boundary([-2,2]).
|
|
361
|
+
pc.filter_atoms(lambda a: a.index in pc.data.types.Ga) # FINE
|
|
362
|
+
pc.set_boundary([-2,2]).filter_atoms(lambda a: a.index in pc.data.types.Ga) # INCORRECT sites picked
|
|
363
|
+
pc.set_boundary([-2,2]).filter_atoms(lambda a: a.index in pc.last.data.types.Ga) # PERFECT, pc.last is output of set_boundary
|
|
364
364
|
```
|
|
365
365
|
"""
|
|
366
366
|
return self._last
|
|
@@ -699,10 +699,10 @@ class POSCAR:
|
|
|
699
699
|
def set_boundary(self, a = [0,1], b=[0,1],c=[0,1]):
|
|
700
700
|
return self.__class__(data = plat.set_boundary(self.data, a=a,b=b,c=c))
|
|
701
701
|
|
|
702
|
-
@_sub_doc(plat.
|
|
703
|
-
@_sig_kwargs(plat.
|
|
704
|
-
def
|
|
705
|
-
return self.__class__(data = plat.
|
|
702
|
+
@_sub_doc(plat.filter_atoms)
|
|
703
|
+
@_sig_kwargs(plat.filter_atoms,("poscar_data",))
|
|
704
|
+
def filter_atoms(self, func, tol=0.01):
|
|
705
|
+
return self.__class__(data = plat.filter_atoms(self.data, func,tol=tol))
|
|
706
706
|
|
|
707
707
|
@_sub_doc(plat.rotate_poscar)
|
|
708
708
|
def rotate(self, angle_deg, axis_vec):
|
|
@@ -181,7 +181,7 @@ class Files:
|
|
|
181
181
|
return self.__class__(files, exclude=exclude,dirs_only=dirs_only,files_only=files_only)
|
|
182
182
|
|
|
183
183
|
def summarize(self, func, **kwargs):
|
|
184
|
-
"Apply a func(
|
|
184
|
+
"Apply a func(path) -> dict and create a dataframe."
|
|
185
185
|
return summarize(self._files,func, **kwargs)
|
|
186
186
|
|
|
187
187
|
def load_results(self):
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.9.7"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|