Skip to content

Commit

Permalink
Merge branch 'master' into aims_kpoint_density_fix
Browse files Browse the repository at this point in the history
  • Loading branch information
tpurcell90 authored Jul 30, 2024
2 parents e619255 + 5256fce commit e3a1a1e
Show file tree
Hide file tree
Showing 29 changed files with 482 additions and 131 deletions.
4 changes: 0 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
__pycache__/
.DS_Store
pymatgen.egg-info
dependencies/PyCifRW-3.3/PyCifRW.egg-info
dependencies/spglib*/pyspglib.egg-info
dependencies/spglib*/build
*.o
*.so
*.pyc
Expand All @@ -26,7 +23,6 @@ setuptools*
.cache
.tox
.eggs/
gulptmp_4_1
.coverage
.*_cache
# VS Code
Expand Down
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ ci:

repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.5.0
rev: v0.5.4
hooks:
- id: ruff
args: [ --fix, --unsafe-fixes ]
Expand All @@ -22,7 +22,7 @@ repos:
- id: trailing-whitespace

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.10.1
rev: v1.11.0
hooks:
- id: mypy

Expand Down Expand Up @@ -65,6 +65,6 @@ repos:
args: [ --drop-empty-cells, --keep-output ]

- repo: https://github.com/RobertCraigie/pyright-python
rev: v1.1.369
rev: v1.1.373
hooks:
- id: pyright
6 changes: 2 additions & 4 deletions src/pymatgen/analysis/graphs.py
Original file line number Diff line number Diff line change
Expand Up @@ -808,8 +808,7 @@ def get_coordination_of_site(self, n: int) -> int:
Returns:
int: number of neighbors of site n.
"""
n_self_loops = sum(1 for n, v in self.graph.edges(n) if n == v)
return self.graph.degree(n) - n_self_loops
return self.graph.degree(n)

def draw_graph_to_file(
self,
Expand Down Expand Up @@ -2478,8 +2477,7 @@ def get_coordination_of_site(self, n) -> int:
Returns:
int: the number of neighbors of site n.
"""
n_self_loops = sum(1 for n, v in self.graph.edges(n) if n == v)
return self.graph.degree(n) - n_self_loops
return self.graph.degree(n)

def draw_graph_to_file(
self,
Expand Down
2 changes: 1 addition & 1 deletion src/pymatgen/analysis/local_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -3048,7 +3048,7 @@ def get_order_parameters(
norms[idx][j][kc] += 1

for m in range(n_neighbors):
if (m != j) and (m != k) and (not flag_xaxis):
if m not in {j, k} and (not flag_xaxis):
tmp = max(-1.0, min(np.inner(zaxis, rij_norm[m]), 1.0))
thetam = math.acos(tmp)
x_two_axis_tmp = gramschmidt(rij_norm[m], zaxis)
Expand Down
2 changes: 1 addition & 1 deletion src/pymatgen/analysis/magnetism/jahnteller.py
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ def _get_number_of_d_electrons(species: Species) -> float:

# taken from get_crystal_field_spin
elec = species.element.full_electronic_structure
if len(elec) < 4 or elec[-1][1] != "s" or elec[-2][1] != "d":
if len(elec) < 4 or elec[-2][1] != "s" or elec[-1][1] != "d":
raise AttributeError(f"Invalid element {species.symbol} for crystal field calculation.")
n_electrons = int(elec[-1][2] + elec[-2][2] - species.oxi_state) # type: ignore[operator]
if n_electrons < 0 or n_electrons > 10:
Expand Down
5 changes: 4 additions & 1 deletion src/pymatgen/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,12 @@
def _load_pmg_settings() -> dict[str, Any]:
settings: dict[str, Any] = {}

# PMG_CONFIG_FILE takes precedence over default settings location
settings_file = os.getenv("PMG_CONFIG_FILE") or SETTINGS_FILE

# Load .pmgrc.yaml file
yaml = YAML()
for file_path in (SETTINGS_FILE, OLD_SETTINGS_FILE):
for file_path in (settings_file, OLD_SETTINGS_FILE):
try:
with open(file_path, encoding="utf-8") as yml_file:
settings = yaml.load(yml_file) or {}
Expand Down
2 changes: 1 addition & 1 deletion src/pymatgen/core/composition.py
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ def chemical_system(self) -> str:
sorted alphabetically and joined by dashes, by convention for use
in database keys.
"""
return "-".join(sorted(el.symbol for el in self.elements))
return "-".join(sorted(self.chemical_system_set))

@property
def num_atoms(self) -> float:
Expand Down
50 changes: 44 additions & 6 deletions src/pymatgen/core/periodic_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,28 @@

_pt_row_sizes = (2, 8, 8, 18, 18, 32, 32)

_madelung = [
(1, "s"),
(2, "s"),
(2, "p"),
(3, "s"),
(3, "p"),
(4, "s"),
(3, "d"),
(4, "p"),
(5, "s"),
(4, "d"),
(5, "p"),
(6, "s"),
(4, "f"),
(5, "d"),
(6, "p"),
(7, "s"),
(5, "f"),
(6, "d"),
(7, "p"),
]


@functools.total_ordering
@unique
Expand Down Expand Up @@ -422,11 +444,12 @@ def icsd_oxidation_states(self) -> tuple[int, ...]:
@property
def full_electronic_structure(self) -> list[tuple[int, str, int]]:
"""Full electronic structure as list of tuples, in order of increasing
principal (n) and angular momentum (l) quantum numbers.
energy level (according to the Madelung rule). Therefore, the final
element in the list gives the electronic structure of the valence shell.
For example, the electronic structure for Fe is represented as:
[(1, "s", 2), (2, "s", 2), (2, "p", 6), (3, "s", 2), (3, "p", 6),
(3, "d", 6), (4, "s", 2)].
(4, "s", 2), (3, "d", 6)].
References:
Kramida, A., Ralchenko, Yu., Reader, J., and NIST ASD Team (2023). NIST
Expand All @@ -445,7 +468,13 @@ def parse_orbital(orb_str):
if data[0][0] == "[":
sym = data[0].replace("[", "").replace("]", "")
data = list(Element(sym).full_electronic_structure) + data[1:]
return data
# sort the final electronic structure by increasing energy level
return sorted(data, key=lambda x: _madelung.index((x[0], x[1])))

@property
def n_electrons(self) -> int:
"""Total number of electrons in the Element."""
return sum([t[-1] for t in self.full_electronic_structure])

@property
def valence(self) -> tuple[int | np.nan, int]:
Expand Down Expand Up @@ -1117,7 +1146,8 @@ def electronic_structure(self) -> str:
@property
def full_electronic_structure(self) -> list[tuple[int, str, int]]:
"""Full electronic structure as list of tuples, in order of increasing
principal (n) and angular momentum (l) quantum numbers.
energy level (according to the Madelung rule). Therefore, the final
element in the list gives the electronic structure of the valence shell.
For example, the electronic structure for Fe+2 is represented as:
[(1, "s", 2), (2, "s", 2), (2, "p", 6), (3, "s", 2), (3, "p", 6),
Expand All @@ -1140,7 +1170,15 @@ def parse_orbital(orb_str):
if data[0][0] == "[":
sym = data[0].replace("[", "").replace("]", "")
data = list(Element(sym).full_electronic_structure) + data[1:]
return data
# sort the final electronic structure by increasing energy level
return sorted(data, key=lambda x: _madelung.index((x[0], x[1])))

# NOTE - copied exactly from Element. Refactoring / inheritance may improve
# robustness
@property
def n_electrons(self) -> int:
"""Total number of electrons in the Species."""
return sum([t[-1] for t in self.full_electronic_structure])

# NOTE - copied exactly from Element. Refactoring / inheritance may improve
# robustness
Expand Down Expand Up @@ -1319,7 +1357,7 @@ def get_crystal_field_spin(
raise ValueError("Invalid coordination or spin config")

elec = self.element.full_electronic_structure
if len(elec) < 4 or elec[-1][1] != "s" or elec[-2][1] != "d":
if len(elec) < 4 or elec[-2][1] != "s" or elec[-1][1] != "d":
raise AttributeError(f"Invalid element {self.symbol} for crystal field calculation")

assert self.oxi_state is not None
Expand Down
37 changes: 17 additions & 20 deletions src/pymatgen/electronic_structure/boltztrap.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
"""This module provides classes to run and analyze boltztrap on pymatgen band
structure objects. Boltztrap is a software interpolating band structures and
computing materials properties from this band structure using Boltzmann
semi-classical transport theory.
"""This module provides classes to run and analyze BoltzTraP on pymatgen band
structure objects. BoltzTraP is a software developed by Georg Madsen to
interpolate band structures and compute materials properties from this
band structure using Boltzmann semi-classical transport theory.
Boltztrap has been developed by Georg Madsen.
http://www.icams.de/content/research/software-development/boltztrap/
https://www.tuwien.at/en/tch/tc/theoretical-materials-chemistry/boltztrap
You need version 1.2.3 or higher
References are:
References:
Madsen, G. K. H., and Singh, D. J. (2006).
BoltzTraP. A code for calculating band-structure dependent quantities.
Computer Physics Communications, 175, 67-71
Expand Down Expand Up @@ -60,13 +57,13 @@


class BoltztrapRunner(MSONable):
"""This class is used to run Boltztrap on a band structure object."""
"""This class is used to run BoltzTraP on a band structure object."""

@requires(
which("x_trans"),
"BoltztrapRunner requires the executables 'x_trans' to be in PATH. Please download "
"Boltztrap at http://www.icams.de/content/research/software-development/boltztrap/ "
"and follow the instructions in the README to compile Bolztrap accordingly. "
"BoltzTraP at https://www.tuwien.at/en/tch/tc/theoretical-materials-chemistry/boltztrap "
"and follow the instructions in the README to compile BoltzTraP accordingly. "
"Then add x_trans to your path",
)
def __init__(
Expand Down Expand Up @@ -144,7 +141,7 @@ def __init__(
electron occupations. If the band structure comes from a soc
computation, you should set soc to True (default False)
doping:
the fixed doping levels you want to compute. Boltztrap provides
the fixed doping levels you want to compute. BoltzTraP provides
both transport values depending on electron chemical potential
(fermi energy) and for a series of fixed carrier
concentrations. By default, this is set to 1e16 to 1e22 in
Expand Down Expand Up @@ -734,7 +731,7 @@ def __init__(
bz_kpoints=None,
fermi_surface_data=None,
) -> None:
"""Constructor taking directly all the data generated by Boltztrap. You
"""Constructor taking directly all the data generated by BoltzTraP. You
won't probably use it directly but instead use the from_files and
from_dict methods.
Expand All @@ -760,7 +757,7 @@ def __init__(
each Fermi level in mu_steps]}
The units are m^3/C
doping: The different doping levels that have been given to
Boltztrap. The format is {'p':[],'n':[]} with an array of
BoltzTraP. The format is {'p':[],'n':[]} with an array of
doping levels. The units are cm^-3
mu_doping: Gives the electron chemical potential (or Fermi level)
for a given set of doping.
Expand Down Expand Up @@ -802,7 +799,7 @@ def __init__(
intrans: a dictionary of inputs e.g. {"scissor": 0.0}
carrier_conc: The concentration of carriers in electron (or hole)
per unit cell
dos: The dos computed by Boltztrap given as a pymatgen Dos object
dos: The dos computed by BoltzTraP given as a pymatgen Dos object
dos_partial: Data for the partial DOS projected on sites and
orbitals
vol: Volume of the unit cell in angstrom cube (A^3)
Expand Down Expand Up @@ -837,13 +834,13 @@ def __init__(
self.fermi_surface_data = fermi_surface_data

def get_symm_bands(self, structure: Structure, efermi, kpt_line=None, labels_dict=None):
"""Useful to read bands from Boltztrap output and get a BandStructureSymmLine object
"""Useful to read bands from BoltzTraP output and get a BandStructureSymmLine object
comparable with that one from a DFT calculation (if the same kpt_line is
provided). Default kpt_line and labels_dict is the standard path of high symmetry
k-point for the specified structure. They could be extracted from the
BandStructureSymmLine object that you want to compare with. efermi variable must
be specified to create the BandStructureSymmLine object (usually it comes from DFT
or Boltztrap calc).
or BoltzTraP calc).
"""
try:
if kpt_line is None:
Expand Down Expand Up @@ -1640,7 +1637,7 @@ def get_carrier_concentration(self):

def get_hall_carrier_concentration(self):
"""Get the Hall carrier concentration (in cm^-3). This is the trace of
the Hall tensor (see Boltztrap source code) Hall carrier concentration
the Hall tensor (see BoltzTraP source code) Hall carrier concentration
are not always exactly the same than carrier concentration.
Returns:
Expand Down Expand Up @@ -1770,7 +1767,7 @@ def parse_intrans(path_dir):
path_dir: (str) dir containing the boltztrap.intrans file
Returns:
dict: various inputs that had been used in the Boltztrap run.
dict: various inputs that had been used in the BoltzTraP run.
"""
intrans = {}
with open(f"{path_dir}/boltztrap.intrans") as file:
Expand Down
28 changes: 27 additions & 1 deletion src/pymatgen/ext/matproj.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ def get_summary_by_material_id(self, material_id: str, fields: list | None = Non
Dict
"""
get = "_all_fields=True" if fields is None else "_fields=" + ",".join(fields)
return self.request(f"materials/summary/{material_id}/?{get}")[0]
return self.request(f"materials/summary/?{get}", payload={"material_ids": material_id})[0]

get_doc = get_summary_by_material_id

Expand Down Expand Up @@ -349,6 +349,32 @@ def get_entries_in_chemsys(self, elements, *args, **kwargs):

return self.get_entries(criteria, *args, **kwargs)

def get_phonon_bandstructure_by_material_id(self, material_id: str):
"""Get phonon bandstructure by material_id.
Args:
material_id (str): Materials Project material_id
Returns:
PhononBandStructureSymmLine: A phonon band structure.
"""
prop = "ph_bs"
response = self.request(f"materials/phonon/?material_ids={material_id}&_fields={prop}")
return response[0][prop]

def get_phonon_dos_by_material_id(self, material_id: str):
"""Get phonon density of states by material_id.
Args:
material_id (str): Materials Project material_id
Returns:
CompletePhononDos: A phonon DOS object.
"""
prop = "ph_dos"
response = self.request(f"materials/phonon/?material_ids={material_id}&_fields={prop}")
return response[0][prop]


class MPRester:
"""A class to conveniently interface with the new and legacy Materials Project REST interface.
Expand Down
21 changes: 21 additions & 0 deletions src/pymatgen/io/abinit/netcdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from pymatgen.core.structure import Structure
from pymatgen.core.units import ArrayWithUnit
from pymatgen.core.xcfunc import XcFunc
from pymatgen.electronic_structure.core import Magmom

if TYPE_CHECKING:
from typing_extensions import Self
Expand Down Expand Up @@ -315,6 +316,23 @@ def structure_from_ncdata(ncdata, site_properties=None, cls=Structure):
# type_atom[:natom] --> index Between 1 and number of atom species
type_atom = ncdata.read_value("atom_species")

try:
intgden = ncdata.read_value("intgden")
nspden = intgden.shape[1]
except NetcdfReaderError:
intgden = None
nspden = None

if intgden is not None:
if nspden == 2:
magmoms = Magmom(intgden[:, 1] - intgden[:, 0])
elif nspden == 4:
magmoms = [Magmom([intg_at[1], intg_at[2], intg_at[3]]) for intg_at in intgden]
else:
magmoms = None
else:
magmoms = None

# Fortran to C index and float --> int conversion.
species = n_atom * [None]
for atom in range(n_atom):
Expand All @@ -326,6 +344,9 @@ def structure_from_ncdata(ncdata, site_properties=None, cls=Structure):
for prop in site_properties:
dct[prop] = ncdata.read_value(prop)

if magmoms is not None and "magmom" not in dct:
dct["magmom"] = magmoms

structure = cls(lattice, species, red_coords, site_properties=dct)

# Quick and dirty hack.
Expand Down
Loading

0 comments on commit e3a1a1e

Please sign in to comment.