ipyvasp 0.9.0__py2.py3-none-any.whl → 0.9.1__py2.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.
ipyvasp/_lattice.py CHANGED
@@ -1440,21 +1440,21 @@ def _fix_sites(
1440
1440
  labels = np.array(poscar_data.labels) # We need to store equivalent labels as well
1441
1441
  out_dict = poscar_data.to_dict() # For output
1442
1442
 
1443
- if translate and isinstance(translate, (int, np.integer, float)):
1443
+ if isinstance(translate, (int, np.integer, float)):
1444
1444
  pos = pos + (translate - int(translate)) # Only translate in 0 - 1
1445
- elif translate and len(translate) == 3:
1445
+ elif isinstance(translate,(tuple, list, np.ndarray)) and len(translate) == 3:
1446
1446
  txyz = np.array([translate])
1447
1447
  pos = pos + (txyz - txyz.astype(int))
1448
1448
 
1449
1449
  # Fix coordinates of sites distributed on edges and faces
1450
- if not hasattr(poscar_data.metadata, 'source_indices'): # no more fixing over there
1450
+ if getattr(poscar_data.metadata, 'eqv_fix', True): # no more fixing over there
1451
1451
  pos -= (pos > (1 - tol)).astype(int) # Move towards orign for common fixing like in joining POSCARs
1452
1452
 
1453
1453
  out_dict["positions"] = pos
1454
1454
  out_dict["metadata"]["comment"] = "Modified by ipyvasp"
1455
1455
 
1456
1456
  # Add equivalent sites on edges and faces if given,handle each sepecies separately
1457
- if eqv_sites:
1457
+ if eqv_sites and getattr(poscar_data.metadata, 'eqv_fix', True):
1458
1458
  new_dict, start = {}, 0
1459
1459
  for k, v in out_dict["types"].items():
1460
1460
  vpos = pos[v]
@@ -1462,7 +1462,7 @@ def _fix_sites(
1462
1462
  inds = np.array(v)
1463
1463
 
1464
1464
  ivpos = np.concatenate([np.indices((len(vpos),)).reshape((-1,1)),vpos],axis=1) # track of indices
1465
- ivpos = np.array([ivpos + [0, *p] for p in set(product([-1,0,1],[-1,0,1],[-1,0,1]))]).reshape((-1,4))
1465
+ ivpos = np.array([ivpos + [0, *p] for p in product([-1,0,1],[-1,0,1],[-1,0,1])]).reshape((-1,4))
1466
1466
  ivpos = ivpos[(ivpos[:,1:] > -tol).all(axis=1) & (ivpos[:,1:] < 1 + tol).all(axis=1)]
1467
1467
  ivpos = ivpos[ivpos[:,0].argsort()]
1468
1468
  idxs = ivpos[:,0].ravel().astype(int).tolist()
@@ -1563,9 +1563,7 @@ def _masked_data(poscar_data, func):
1563
1563
  if not isinstance(func(0, 0, 0, 0), bool):
1564
1564
  raise TypeError("`func` should return a boolean value.")
1565
1565
 
1566
- eqv_inds = None
1567
- if hasattr(poscar_data.metadata, "eqv_indices"):
1568
- eqv_inds = tuple(poscar_data.metadata.eqv_indices)
1566
+ eqv_inds = tuple(getattr(poscar_data.metadata, "eqv_indices",[]))
1569
1567
 
1570
1568
  pick = []
1571
1569
  for i, pos in enumerate(poscar_data.positions):
@@ -1595,6 +1593,8 @@ def filter_sites(poscar_data, func, tol = 0.01):
1595
1593
  """Filter sites based on a function that acts on index and fractional positions such as `lambda i,x,y,z: condition`.
1596
1594
  This may include equivalent sites, so it should be used for plotting purpose only, e.g. showing atoms on a plane.
1597
1595
  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]`.
1596
+
1597
+ 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.
1598
1598
  """
1599
1599
  if hasattr(poscar_data.metadata, 'source_indices'):
1600
1600
  raise ValueError("Cannot filter an already filtered POSCAR data.")
@@ -1602,10 +1602,12 @@ def filter_sites(poscar_data, func, tol = 0.01):
1602
1602
  poscar_data = _fix_sites(poscar_data, tol = tol, eqv_sites=True)
1603
1603
  idxs = _masked_data(poscar_data, func)
1604
1604
  data = poscar_data.to_dict()
1605
+ eqvi = data['metadata'].pop('eqv_indices', []) # no need of this
1606
+
1605
1607
  all_pos, npos, eqv_labs, finds = [], [0,],[],[]
1606
1608
  for value in poscar_data.types.values():
1607
1609
  indices = [i for i in value if i in idxs] # search from value make sure only non-equivalent sites added
1608
- finds.extend(poscar_data.metadata.eqv_indices[indices])
1610
+ finds.extend(eqvi[indices] if len(eqvi) else indices)
1609
1611
  eqv_labs.extend(poscar_data.labels[indices])
1610
1612
  pos = data['positions'][indices]
1611
1613
  all_pos.append(pos)
@@ -1616,8 +1618,8 @@ def filter_sites(poscar_data, func, tol = 0.01):
1616
1618
 
1617
1619
  data['positions'] = np.concatenate(all_pos, axis = 0)
1618
1620
  data['metadata']['source_indices'] = np.array(finds)
1621
+ data['metadata']['eqv_fix'] = False
1619
1622
  data['metadata']['eqv_labels'] = np.array(eqv_labs) # need these for compare to previous
1620
- data['metadata'].pop('eqv_indices', None) # no need of this
1621
1623
 
1622
1624
  ranges = np.cumsum(npos)
1623
1625
  data['types'] = {key: range(i,j) for key, i,j in zip(data['types'],ranges[:-1],ranges[1:]) if range(i,j)} # avoid empty
@@ -2204,7 +2206,7 @@ def scale_poscar(poscar_data, scale=(1, 1, 1), tol=1e-2):
2204
2206
  return serializer.PoscarData(new_poscar)
2205
2207
 
2206
2208
  def set_boundary(poscar_data, a = [0,1], b = [0,1], c = [0,1]):
2207
- "View atoms outside cell boundary along a,b,c directions."
2209
+ "View atoms in a given boundary along a,b,c directions."
2208
2210
  for d, name in zip([a,b,c],'abc'):
2209
2211
  if not isinstance(d,(list,tuple)) or len(d) != 2:
2210
2212
  raise ValueError(f"{name} should be a list/tuple of type [min, max]")
@@ -2216,17 +2218,13 @@ def set_boundary(poscar_data, a = [0,1], b = [0,1], c = [0,1]):
2216
2218
  for key, value in poscar_data.types.items():
2217
2219
  pos = data['positions'][value]
2218
2220
  for i, (l,h), shift in zip(range(3), [a,b,c],np.eye(3)):
2219
- while pos[:,i].min() > np.floor(l):
2220
- pos = np.concatenate([pos, pos - shift],axis=0)
2221
-
2222
- while pos[:,i].max() < np.ceil(h):
2223
- pos = np.concatenate([pos, pos + shift],axis=0)
2224
-
2221
+ pos = np.concatenate([pos + shift*k for k in np.arange(np.floor(l), np.ceil(h))],axis=0)
2225
2222
  pos = pos[(pos[:,i] >= l) & (pos[:,i] <= h)]
2226
2223
 
2227
2224
  upos[key] = pos
2228
2225
 
2229
2226
  data['positions'] = np.concatenate(list(upos.values()), axis = 0)
2227
+ data['metadata']['eqv_fix'] = False
2230
2228
 
2231
2229
  ranges = np.cumsum([0, *[len(v) for v in upos.values()]])
2232
2230
  data['types'] = {key: range(i,j) for key, i,j in zip(upos,ranges[:-1],ranges[1:])}
@@ -2256,20 +2254,6 @@ def rotate_poscar(poscar_data, angle_deg, axis_vec):
2256
2254
  p_dict["metadata"]["comment"] = f"Modified by ipyvasp"
2257
2255
  return serializer.PoscarData(p_dict)
2258
2256
 
2259
-
2260
- def set_origin(poscar_data, origin):
2261
- """Set origin of POSCAR sites to a given position in fractional coordinates.
2262
- The following example demonstrates the use of this function.
2263
-
2264
- >>> import ipyvasp as ipv
2265
- >>> poscar = ipv.POSCAR("POSCAR")
2266
- >>> ax = poscar.splot_cell() # plot original cell
2267
- >>> poscar_shifted = poscar.scale((3,3,3)).set_origin((1/3,1/3,1/3))
2268
- >>> poscar_shifted.splot_lattice(ax=ax, plot_cell=False) # displays sites around original cell
2269
- """
2270
- return _fix_sites(poscar_data, eqv_sites=False, origin=origin)
2271
-
2272
-
2273
2257
  def set_zdir(poscar_data, hkl, phi=0):
2274
2258
  """Set z-direction of POSCAR along a given hkl direction and returns new data.
2275
2259
 
@@ -2401,7 +2385,7 @@ def transform_poscar(poscar_data, transformation, fill_factor=2, tol=1e-2):
2401
2385
 
2402
2386
  _p = range(-fill_factor, fill_factor + 1)
2403
2387
  pos = np.concatenate([poscar_data.positions,[[i] for i,_ in enumerate(poscar_data.positions)]], axis=1) # keep track of index
2404
- pos = np.concatenate([pos + [*p,0] for p in set(product(_p,_p,_p))],axis=0) # increaser by fill_factor^3
2388
+ pos = np.concatenate([pos + [*p,0] for p in product(_p,_p,_p)],axis=0) # increaser by fill_factor^3
2405
2389
  pos[:,:3] = to_basis(new_basis, poscar_data.to_cartesian(pos[:,:3])) # convert to coords in this and to points in new
2406
2390
  pos = pos[(pos[:,:3] <= 1 - tol).all(axis=1) & (pos[:,:3] >= -tol).all(axis=1)]
2407
2391
  pos = pos[pos[:,-1].argsort()] # sort for species
ipyvasp/_version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.9.0"
1
+ __version__ = "0.9.1"
@@ -328,6 +328,15 @@ class PoscarData(Dict2Data):
328
328
  def symbols(self):
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
+
332
+ def get_sites(self, type_or_indices, as_coords=False):
333
+ "Shortcut method for `POSCAR.data.positions[POSCAR.data.types['name']]` or with regular indexing."
334
+ points = self.coords if as_coords else self.positions
335
+ if isinstance(type_or_indices,str) and type_or_indices in self.types:
336
+ return points[self.types[type_or_indices]]
337
+ elif not isinstance(type_or_indices,(list,range,tuple)):
338
+ raise TypeError("type_or_indices should be a species type like 'Ga' or list-like of indices to pick positions.")
339
+ return points[type_or_indices]
331
340
 
332
341
  def get_neighbors(self, k=5):
333
342
  """Get the k nearest neighbors of each atom (including itself) in the lattice.
@@ -390,7 +399,7 @@ class PoscarData(Dict2Data):
390
399
 
391
400
  dists = []
392
401
  for idx in idx1:
393
- for trans in set(product([-1,0,1],[-1,0,1],[-1,0,1])):
402
+ for trans in product([-1,0,1],[-1,0,1],[-1,0,1]):
394
403
  C = self.to_cartesian(self.positions[idx] + trans) # translate around to get lowest distance
395
404
 
396
405
  dists = [
@@ -412,7 +421,7 @@ class PoscarData(Dict2Data):
412
421
  for i in self.types[type1]:
413
422
  for j in [k for k in self.types[type2] if k != i]:
414
423
  a = self.coords[i]
415
- bs = [self.to_cartesian(self.positions[j] + p) for p in set(product([-1,0,1],[-1,0,1],[-1,0,1]))]
424
+ bs = [self.to_cartesian(self.positions[j] + p) for p in product([-1,0,1],[-1,0,1],[-1,0,1])]
416
425
  ds = np.array([np.linalg.norm(a-b) for b in bs])
417
426
  d = ds[ds > 0].min() # no same site distance
418
427
  if min < d < max:
ipyvasp/lattice.py CHANGED
@@ -256,18 +256,18 @@ class _AutoRenderer:
256
256
  _figw = None
257
257
  _kws = {}
258
258
 
259
- def __init__(self, pc_instance):
260
- self._pc = pc_instance
259
+ def __init__(self, pc_cls):
260
+ self._pc = pc_cls
261
261
 
262
262
  def on(self, template=None):
263
263
  "Enable auto rendering. In Jupyterlab, you can use `Create New View for Output` to drag a view on side."
264
264
  self.off()
265
- type(self)._figw = iplot2widget(self._pc.iplot_lattice(**self._kws), fig_widget=self._figw,template=template)
265
+ type(self)._figw = iplot2widget(self._pc._last.iplot_lattice(**self._kws), fig_widget=self._figw,template=template)
266
266
 
267
267
  def ip_display(that):
268
268
  iplot2widget(that.iplot_lattice(**self._kws), fig_widget=self._figw, template=template)
269
269
 
270
- type(self._pc)._ipython_display_ = ip_display
270
+ self._pc._ipython_display_ = ip_display
271
271
 
272
272
  from ipywidgets import Button, VBox
273
273
  btn = Button(description='Disable Auto Rendering',icon='close',layout={'width': 'max-content'})
@@ -281,14 +281,14 @@ class _AutoRenderer:
281
281
  self._box.close()
282
282
  type(self)._figw = None # no need to close figw, it raise warning, but now garbage collected
283
283
 
284
- if hasattr(type(self._pc), '_ipython_display_'):
285
- del type(self._pc)._ipython_display_
284
+ if hasattr(self._pc, '_ipython_display_'):
285
+ del self._pc._ipython_display_
286
286
 
287
287
  @_sig_kwargs(plat.iplot_lattice,('poscar_data',))
288
288
  def update_params(self, **kwargs):
289
289
  type(self)._kws = kwargs
290
- if hasattr(type(self._pc), '_ipython_display_'):
291
- self._pc._ipython_display_()
290
+ if hasattr(self._pc, '_ipython_display_'):
291
+ self._pc._last._ipython_display_()
292
292
 
293
293
  @property
294
294
  def params(self):
@@ -304,7 +304,6 @@ class POSCAR:
304
304
  def __init__(self, path=None, content=None, data=None):
305
305
  """
306
306
  POSCAR class to contain data and related methods, data is PoscarData, json/tuple file/string.
307
- Do not use `data` yourself, it's for operations on poscar.
308
307
 
309
308
  Parameters
310
309
  ----------
@@ -314,14 +313,20 @@ class POSCAR:
314
313
 
315
314
  Prefrence order: data > content > path
316
315
 
316
+ Note: During chained operations where functions are acting on index of sites, use `self.last` instead of `self` to point to latest POSCAR in chain.
317
+
318
+ ```python
319
+ pc = POSCAR()
320
+ pc.filter_sites(lambda i,x,y,z: i in pc.data.types.Ga) # FINE
321
+ pc.set_boundary([-2,2]).filter_sites(lambda i,x,y,z: i in pc.data.types.Ga) # INCORRECT sites may be picked
322
+ pc.set_boundary([-2,2]).filter_sites(lambda i,x,y,z: i in pc.last.data.types.Ga) # PERFECT, pc.last is output of set_boundary
323
+ ```
324
+
317
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.
318
326
  """
319
327
  self._path = Path(path or "POSCAR") # Path to file
320
328
  self._content = content
321
-
322
- if not hasattr(self, '_renderer'): # Only once
323
- type(self)._renderer = _AutoRenderer(self) # assign to class
324
- self._renderer._pc = self # keep latest refrence there too, for update_params on right one
329
+ self.__class__._last = self # need this to access in lambda in chain operations
325
330
 
326
331
  if data:
327
332
  self._data = serializer.PoscarData.validated(data)
@@ -347,6 +352,19 @@ class POSCAR:
347
352
  def path(self):
348
353
  return self._path
349
354
 
355
+ @property
356
+ def last(self):
357
+ """Points to last created POSCAR instance during chained operations!
358
+
359
+ ```python
360
+ pc = POSCAR()
361
+ pc.filter_sites(lambda i,x,y,z: i in pc.data.types.Ga) # FINE
362
+ pc.set_boundary([-2,2]).filter_sites(lambda i,x,y,z: i in pc.data.types.Ga) # INCORRECT sites may be picked
363
+ pc.set_boundary([-2,2]).filter_sites(lambda i,x,y,z: i in pc.last.data.types.Ga) # PERFECT, pc.last is output set_boundary
364
+ ```
365
+ """
366
+ return self._last
367
+
350
368
  @property
351
369
  def auto_renderer(self):
352
370
  """A renderer for auto viewing POSCAR when at last line of cell.
@@ -358,6 +376,8 @@ class POSCAR:
358
376
  In Jupyterlab, you can use `Create New View for Output` to drag a view on side.
359
377
  In VS Code, you can open another view of Notebook to see it on side while doing operations.
360
378
  """
379
+ if not hasattr(self, '_renderer'):
380
+ self.__class__._renderer = _AutoRenderer(self.__class__) # assign to class
361
381
  return self._renderer
362
382
 
363
383
  def to_ase(self):
@@ -684,10 +704,6 @@ class POSCAR:
684
704
  def filter_sites(self, func, tol=0.01):
685
705
  return self.__class__(data = plat.filter_sites(self.data, func,tol=tol))
686
706
 
687
- @_sub_doc(plat.set_origin)
688
- def set_origin(self, origin):
689
- return self.__class__(data=plat.set_origin(self.data, origin=origin))
690
-
691
707
  @_sub_doc(plat.rotate_poscar)
692
708
  def rotate(self, angle_deg, axis_vec):
693
709
  return self.__class__(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ipyvasp
3
- Version: 0.9.0
3
+ Version: 0.9.1
4
4
  Summary: A processing tool for VASP DFT input/output processing in Jupyter Notebook.
5
5
  Home-page: https://github.com/massgh/ipyvasp
6
6
  Author: Abdul Saboor
@@ -1,12 +1,12 @@
1
1
  ipyvasp/__init__.py,sha256=7o41i5eYlNKg1Hsv0DLNFZ81GilxB02IXAJN-QiJQi0,1420
2
2
  ipyvasp/__main__.py,sha256=eJV1TZSiT8mC_VqAeksNnBI2I8mKMiPkEIlwikbtOjI,216
3
3
  ipyvasp/_enplots.py,sha256=D38paN8zqZgluNAwmCwcocd7-_h_T0HTGolI1eBkDes,37484
4
- ipyvasp/_lattice.py,sha256=ASHTQV3QK4mhx7eO3ISLvzm4fTg5KGiQ3iI0BqfmEac,102978
5
- ipyvasp/_version.py,sha256=Rqk_eJf2ntSg0XlEKqShPvNr_E2rQ3wfdU2Xyp-R4ls,23
4
+ ipyvasp/_lattice.py,sha256=BqlDmokeYgdnWGw8YPGPRm3-wrgteUJg1R3YK9suMLY,102554
5
+ ipyvasp/_version.py,sha256=nowX8dTYmAqqc8x180AcV7Ru6brVwGyJwg9GfVedBCE,23
6
6
  ipyvasp/bsdos.py,sha256=ZtQji-W11UdFFicAoWZjlqVhI5tqYu_jpKyPPWKkeeo,30634
7
7
  ipyvasp/cli.py,sha256=aWFEVhNmnW8eSOp5uh95JaDwLQ9K9nlCQcbnOSuhWgw,6844
8
8
  ipyvasp/evals_dataframe.py,sha256=-sqxK7LPV6sYDO_XXmZ80FznOaXTkVdbqJKKvTUtMak,20637
9
- ipyvasp/lattice.py,sha256=t7lkewCbN8IFUIKia9Xkc8p0pTDBc_34NIrlWsXENGA,29800
9
+ ipyvasp/lattice.py,sha256=wz5CKv5YJbELvG2lbrYnXoT7u9R70Jkr_i3olE4Hx4I,30643
10
10
  ipyvasp/misc.py,sha256=SZJ_ePUR2-HEKYTEpDHVRVE7zpIQVTCjiuw0BCC9UTU,2349
11
11
  ipyvasp/potential.py,sha256=tzA73c5lkp6ahLSJchMrU043-QWaOV0nIOUA7VMmfKQ,11408
12
12
  ipyvasp/surface.py,sha256=MjE5oB0wW6Pca_C-xu8rN6OMH7lUEeNPNyM7Kz_Im-8,23766
@@ -15,11 +15,11 @@ ipyvasp/widgets.py,sha256=fZ2b7EYYxuaAVfklnLa0VJ00U9Uyd7SqXrzt0hbLOvI,45400
15
15
  ipyvasp/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
16
  ipyvasp/core/parser.py,sha256=C3CaZsJbPME_ttYlYy4DXeOdL7dnkXs-cHRwFZL6bio,38058
17
17
  ipyvasp/core/plot_toolkit.py,sha256=8t5svyWbOm-PS7ZvIptnK6F46kp6uwoGNdohPv5dQKA,35962
18
- ipyvasp/core/serializer.py,sha256=57e2ypF18tJI1zZi9kJiHGMBYgXvYEZpLmgnaaDdSk0,36067
18
+ ipyvasp/core/serializer.py,sha256=_Ck51U_N6m4pTOkr3VxPtZumi8znrhneHjHuVtA7qDU,36661
19
19
  ipyvasp/core/spatial_toolkit.py,sha256=8DBYTiBFWJ7OBKuvOPw7UoEVCyNjJhSW0OcudjYZvAw,14748
20
- ipyvasp-0.9.0.dist-info/LICENSE,sha256=F3SO5RiAZOMfmMGf1KOuk2g_c4ObvuBJhd9iBLDgXoQ,1263
21
- ipyvasp-0.9.0.dist-info/METADATA,sha256=q73Rkc1Kx_HfNBgB0LT-4Ca8EFz7wXr_9mgquNeGC9I,2420
22
- ipyvasp-0.9.0.dist-info/WHEEL,sha256=iYlv5fX357PQyRT2o6tw1bN-YcKFFHKqB_LwHO5wP-g,110
23
- ipyvasp-0.9.0.dist-info/entry_points.txt,sha256=C7m0Sjmr14wFjflCkWXLzr5N6-cQj8uJC9n82mUtzt8,44
24
- ipyvasp-0.9.0.dist-info/top_level.txt,sha256=ftziWlMWu_1VpDP1sRTFrkfBnWxAi393HYDVu4wRhUk,8
25
- ipyvasp-0.9.0.dist-info/RECORD,,
20
+ ipyvasp-0.9.1.dist-info/LICENSE,sha256=F3SO5RiAZOMfmMGf1KOuk2g_c4ObvuBJhd9iBLDgXoQ,1263
21
+ ipyvasp-0.9.1.dist-info/METADATA,sha256=1DwFCWMbumZTzK_LrDuuCTvlwinFEewM9RWGm-fa1oU,2420
22
+ ipyvasp-0.9.1.dist-info/WHEEL,sha256=iYlv5fX357PQyRT2o6tw1bN-YcKFFHKqB_LwHO5wP-g,110
23
+ ipyvasp-0.9.1.dist-info/entry_points.txt,sha256=C7m0Sjmr14wFjflCkWXLzr5N6-cQj8uJC9n82mUtzt8,44
24
+ ipyvasp-0.9.1.dist-info/top_level.txt,sha256=ftziWlMWu_1VpDP1sRTFrkfBnWxAi393HYDVu4wRhUk,8
25
+ ipyvasp-0.9.1.dist-info/RECORD,,