20
20
from monty .functools import lazy_property
21
21
from monty .string import is_string , marquee , list_strings
22
22
from monty .termcolor import cprint
23
- from monty .dev import deprecated
23
+ # from monty.dev import deprecated
24
24
from pymatgen .core .structure import Structure as pmg_Structure
25
25
from pymatgen .core .sites import PeriodicSite
26
26
from pymatgen .core .lattice import Lattice
29
29
from abipy .core .symmetries import AbinitSpaceGroup
30
30
from abipy .tools .plotting import add_fig_kwargs , get_ax_fig_plt , get_axarray_fig_plt , add_plotly_fig_kwargs
31
31
from abipy .iotools import as_etsfreader , Visualizer
32
-
32
+ from abipy . tools . typing import Figure
33
33
34
34
35
35
__all__ = [
@@ -170,14 +170,48 @@ def display_structure(obj, **kwargs):
170
170
return nbjsmol_display (structure .to (fmt = "cif" ), ext = ".cif" , ** kwargs )
171
171
172
172
173
- class Structure ( pmg_Structure , NotebookWriter ) :
173
+ def get_structures_from_file ( filepath : PathLike , index ) -> list [ Structure ] :
174
174
"""
175
- Extends :class:`pymatgen.core.structure.Structure` with Abinit-specific methods.
175
+ """
176
+ #if index is None:
177
+ # index = -1
178
+
179
+ if filepath .endswith (".traj" ):
180
+ # ASE trajectory file.
181
+ from ase .atoms import Atoms
182
+ from ase .io import read
183
+ atoms_list = read (filepath , index = index )
184
+ if not isinstance (atoms_list , list ):
185
+ assert isinstance (atoms_list , Atoms )
186
+ atoms_list = [atoms_list ]
187
+
188
+ # TODO: HIST.nc and XDATCAR
189
+ #elif filepath.endswith("_HIST.nc"):
190
+ # from abipy.dynamics.hist import HistFile
191
+ # with HistFile(filepath) as hist:
192
+ # return hist.read_structures(index)
193
+
194
+ #elif filepath.endswith("XDATCAR"):
195
+
196
+ else :
197
+ raise NotImplementedError (f"Don't know how to extract structures with index from { filepath = } " )
198
+
199
+ return [Structure .as_structure (atoms ) for atoms in atoms_list ]
176
200
177
- A jupyter_ notebook documenting the usage of this object is available at
178
- <https://nbviewer.jupyter.org/github/abinit/abitutorials/blob/master/abitutorials/structure.ipynb>
179
201
180
- For the pymatgen project see :cite:`Ong2013`.
202
+ def get_first_and_last_structure_from_file (filepath : PathLike ) -> tuple [Structure ]:
203
+ """
204
+ Helper function to read the first and the last structure from a trajectory file.
205
+ Simplified wrapper around get_structures_from_file.
206
+ """
207
+ first_structure = get_structures_from_file (filepath , index = 0 )[0 ]
208
+ last_structure = get_structures_from_file (filepath , index = - 1 )[0 ]
209
+ return first_structure , last_structure
210
+
211
+
212
+ class Structure (pmg_Structure , NotebookWriter ):
213
+ """
214
+ Extends :class:`pymatgen.core.structure.Structure` with Abinit-specific methods.
181
215
182
216
.. rubric:: Inheritance Diagram
183
217
.. inheritance-diagram:: Structure
@@ -277,8 +311,7 @@ def from_file(cls, filepath: str, primitive: bool = False, sort: bool = False) -
277
311
if closeit : ncfile .close ()
278
312
279
313
elif filepath .endswith (".abi" ) or filepath .endswith (".in" ):
280
- # Abinit input file.
281
- # Here I assume that the input file contains a single structure.
314
+ # Abinit input file. Here I assume that the input file contains a single structure.
282
315
from abipy .abio .abivars import AbinitInputFile
283
316
return AbinitInputFile .from_file (filepath ).structure
284
317
@@ -291,6 +324,7 @@ def from_file(cls, filepath: str, primitive: bool = False, sort: bool = False) -
291
324
#print("initial_structures:\n", out.initial_structures, "\nfinal_structures:\n", out.final_structures)
292
325
if out .final_structures : return out .final_structure
293
326
if out .initial_structures : return out .initial_structure
327
+
294
328
raise ValueError ("Cannot find structure in Abinit output file `%s`" % filepath )
295
329
296
330
elif filepath .endswith (".abivars" ) or filepath .endswith (".ucell" ):
@@ -323,8 +357,7 @@ def from_file(cls, filepath: str, primitive: bool = False, sort: bool = False) -
323
357
from ase .io import read
324
358
except ImportError as exc :
325
359
raise RuntimeError ("ase is required to read xyz files. Use `pip install ase`" ) from exc
326
- atoms = read (filepath )
327
- return cls .as_structure (atoms )
360
+ return cls .as_structure (read (filepath ))
328
361
329
362
else :
330
363
# Invoke pymatgen and change class. Note that AbinitSpacegroup is missing here.
@@ -389,7 +422,6 @@ def from_ase_atoms(cls, atoms) -> Structure:
389
422
@property
390
423
def n_elems (self ) -> int :
391
424
"""Number of types of atoms."""
392
-
393
425
return len (self .types_of_species )
394
426
395
427
def to_ase_atoms (self , calc = None ):
@@ -508,7 +540,6 @@ def zincblende(cls, a, species, units="ang", **kwargs) -> Structure:
508
540
kwargs: All keyword arguments accepted by :class:`pymatgen.Structure`
509
541
510
542
Example::
511
-
512
543
Structure.zincblende(a, ["Zn", "S"])
513
544
"""
514
545
a = pmg_units .Length (a , units ).to ("ang" )
@@ -532,7 +563,6 @@ def rocksalt(cls, a, species, units="ang", **kwargs) -> Structure:
532
563
kwargs: All keyword arguments accepted by :class:`pymatgen.Structure`
533
564
534
565
Example::
535
-
536
566
Structure.rocksalt(a, ["Na", "Cl"])
537
567
"""
538
568
a = pmg_units .Length (a , units ).to ("ang" )
@@ -570,10 +600,9 @@ def ABO3(cls, a, species, units="ang", **kwargs) -> Structure:
570
600
@classmethod
571
601
def from_abistring (cls , string : str ) -> Structure :
572
602
"""
573
- Initialize Structure from string with Abinit input variables.
603
+ Initialize Structure from a string with Abinit input variables.
574
604
"""
575
605
from abipy .abio .abivars import AbinitInputFile , structure_from_abistruct_fmt
576
-
577
606
if "xred_symbols" not in string :
578
607
# Standard (verbose) input file with znucl, typat etc.
579
608
return AbinitInputFile .from_string (string ).structure
@@ -679,12 +708,10 @@ def write_cif_with_spglib_symms(self, filename, symprec=1e-3, angle_tolerance=5.
679
708
symprec (float): If not none, finds the symmetry of the structure
680
709
and writes the cif with symmetry information. Passes symprec
681
710
to the SpacegroupAnalyzer.
682
- significant_figures (int): Specifies precision for formatting of floats.
683
- Defaults to 8.
711
+ significant_figures (int): Specifies precision for formatting of floats. Defaults to 8.
684
712
angle_tolerance (float): Angle tolerance for symmetry finding. Passes
685
- angle_tolerance to the SpacegroupAnalyzer. Used only if symprec
686
- is not None.
687
- ret_string: True to return string
713
+ angle_tolerance to the SpacegroupAnalyzer. Used only if symprec is not None.
714
+ ret_string: True to return string.
688
715
"""
689
716
from pymatgen .io .cif import CifWriter
690
717
cif_str = str (CifWriter (self ,
@@ -722,7 +749,7 @@ def to_abivars(self, enforce_znucl=None, enforce_typat=None, **kwargs) -> dict:
722
749
723
750
@property
724
751
def latex_formula (self ) -> str :
725
- """LaTeX formatted formula. E .g., Fe2O3 is transformed to Fe$_{2}$O$_{3}$."""
752
+ """LaTeX formatted formula: e .g., Fe2O3 is transformed to Fe$_{2}$O$_{3}$."""
726
753
from pymatgen .util .string import latexify
727
754
return latexify (self .formula )
728
755
@@ -743,7 +770,6 @@ def get_abi_string(self, fmt: str = "abinit_input") -> str:
743
770
fmt="abicell" is the lightweight format that uses `xred_symbols`
744
771
This format can be used to include the structure in the input via the structure "abivars:FILE" syntax.
745
772
"""
746
-
747
773
lines = []
748
774
app = lines .append
749
775
@@ -811,8 +837,8 @@ def get_panel(self, with_inputs=True, **kwargs):
811
837
def get_conventional_standard_structure (self , international_monoclinic = True ,
812
838
symprec = 1e-3 , angle_tolerance = 5 ) -> Structure :
813
839
"""
814
- Gives a structure with a conventional cell according to certain
815
- standards. The standards are defined in :cite:`Setyawan2010`
840
+ Gives a structure with a conventional cell according to certain standards.
841
+ The standards are defined in :cite:`Setyawan2010`
816
842
They basically enforce as much as possible norm(a1) < norm(a2) < norm(a3)
817
843
818
844
Returns: The structure in a conventional standardized cell
@@ -822,8 +848,7 @@ def get_conventional_standard_structure(self, international_monoclinic=True,
822
848
return self .__class__ .as_structure (new )
823
849
824
850
def abi_primitive (self , symprec = 1e-3 , angle_tolerance = 5 , no_idealize = 0 ) -> Structure :
825
- #TODO: this should be moved to pymatgen in the get_refined_structure or so ...
826
- # to be considered in February 2016
851
+ #TODO: this should be moved to pymatgen in the get_refined_structure or so ... to be considered in February 2016
827
852
import spglib
828
853
from pymatgen .io .ase import AseAtomsAdaptor
829
854
try :
@@ -943,11 +968,6 @@ def abi_sanitize(self, symprec=1e-3, angle_tolerance=5,
943
968
944
969
return self .__class__ .as_structure (structure )
945
970
946
- #def relax(self, **kwargs) -> Structure:
947
- # new = super().relax(**kwargs)
948
- # new.__class__ = self.__class__
949
- # return new
950
-
951
971
def get_oxi_state_decorated (self , ** kwargs ) -> Structure :
952
972
"""
953
973
Use :class:`pymatgen.analysis.bond_valence.BVAnalyzer` to estimate oxidation states
@@ -976,24 +996,10 @@ def reciprocal_lattice(self):
976
996
"""
977
997
return self ._lattice .reciprocal_lattice
978
998
979
- @deprecated (message = "lattice_vectors is deprecated and will be removed in abipy 1.0" )
980
- def lattice_vectors (self , space = "r" ):
981
- """
982
- Returns the vectors of the unit cell in Angstrom.
983
-
984
- Args:
985
- space: "r" for real space vectors, "g" for reciprocal space basis vectors.
986
- """
987
- if space .lower () == "r" :
988
- return self .lattice .matrix
989
- if space .lower () == "g" :
990
- return self .lattice .reciprocal_lattice .matrix
991
- raise ValueError ("Wrong value for space: %s " % str (space ))
992
-
993
999
def spget_lattice_type (self , symprec = 1e-3 , angle_tolerance = 5 ) -> str :
994
1000
"""
995
1001
Call spglib to get the lattice for the structure, e.g., (triclinic,
996
- orthorhombic, cubic, etc.).This is the same than the
1002
+ orthorhombic, cubic, etc.). This is the same than the
997
1003
crystal system with the exception of the hexagonal/rhombohedral lattice
998
1004
999
1005
Args:
@@ -1627,7 +1633,7 @@ def plotly_bz(self, fig=None, pmg_path=True, with_labels=True, **kwargs):
1627
1633
1628
1634
@add_fig_kwargs
1629
1635
def plot_xrd (self , wavelength = "CuKa" , symprec = 0 , debye_waller_factors = None ,
1630
- two_theta_range = (0 , 90 ), annotate_peaks = True , ax = None , ** kwargs ):
1636
+ two_theta_range = (0 , 90 ), annotate_peaks = True , ax = None , ** kwargs ) -> Figure :
1631
1637
"""
1632
1638
Use pymatgen :class:`XRDCalculator` to show the XRD plot.
1633
1639
0 commit comments