Skip to content

Commit cdf2987

Browse files
authored
Merge branch 'master' into zopen-explicit-mode
2 parents caee02a + 362bf54 commit cdf2987

File tree

97 files changed

+1018
-517
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

97 files changed

+1018
-517
lines changed

.github/workflows/test.yml

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -61,36 +61,34 @@ jobs:
6161
- name: Check out repo
6262
uses: actions/checkout@v4
6363

64-
- name: Set up micromamba
65-
uses: mamba-org/setup-micromamba@main
66-
6764
- name: Create mamba environment
68-
run: |
69-
micromamba create -n pmg python=${{ matrix.config.python }} --yes
65+
uses: mamba-org/setup-micromamba@main
66+
with:
67+
environment-name: pmg
68+
create-args: >-
69+
python=${{ matrix.config.python }}
7070
7171
- name: Install ubuntu-only conda dependencies
7272
if: matrix.config.os == 'ubuntu-latest'
7373
run: |
7474
micromamba install -n pmg -c conda-forge bader enumlib \
7575
openff-toolkit packmol pygraphviz tblite --yes
7676
77+
- name: Install uv
78+
uses: astral-sh/setup-uv@v4
79+
7780
- name: Install pymatgen and dependencies via uv
7881
run: |
7982
micromamba activate pmg
80-
81-
pip install uv
82-
8383
# TODO1 (use uv over pip) uv install torch is flaky, track #3826
8484
# TODO2 (pin torch version): DGL library (matgl) doesn't support torch > 2.2.1,
8585
# see: https://discuss.dgl.ai/t/filenotfounderror-cannot-find-dgl-c-graphbolt-library/4302
8686
pip install torch==2.2.1
8787
8888
# Install from wheels to test the content
89-
uv pip install build
90-
python -m build --wheel
91-
92-
uv pip install dist/*.whl
93-
uv pip install pymatgen[${{ matrix.config.extras }}] --resolution=${{ matrix.config.resolution }}
89+
uv build --wheel --no-build-logs
90+
WHEEL_FILE=$(ls dist/pymatgen*.whl)
91+
uv pip install $WHEEL_FILE[${{matrix.config.extras}}] --resolution=${{matrix.config.resolution}}
9492
9593
- name: Install optional Ubuntu dependencies
9694
if: matrix.config.os == 'ubuntu-latest'

.pre-commit-config.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ ci:
88

99
repos:
1010
- repo: https://github.com/astral-sh/ruff-pre-commit
11-
rev: v0.7.2
11+
rev: v0.8.1
1212
hooks:
1313
- id: ruff
1414
args: [--fix, --unsafe-fixes]
@@ -36,7 +36,7 @@ repos:
3636
exclude: src/pymatgen/analysis/aflow_prototypes.json
3737

3838
- repo: https://github.com/MarcoGorelli/cython-lint
39-
rev: v0.16.2
39+
rev: v0.16.6
4040
hooks:
4141
- id: cython-lint
4242
args: [--no-pycodestyle]
@@ -48,7 +48,7 @@ repos:
4848
- id: blacken-docs
4949

5050
- repo: https://github.com/igorshubovych/markdownlint-cli
51-
rev: v0.42.0
51+
rev: v0.43.0
5252
hooks:
5353
- id: markdownlint
5454
# MD013: line too long
@@ -59,12 +59,12 @@ repos:
5959
args: [--disable, MD013, MD024, MD025, MD033, MD041, "--"]
6060

6161
- repo: https://github.com/kynan/nbstripout
62-
rev: 0.8.0
62+
rev: 0.8.1
6363
hooks:
6464
- id: nbstripout
6565
args: [--drop-empty-cells, --keep-output]
6666

6767
- repo: https://github.com/RobertCraigie/pyright-python
68-
rev: v1.1.387
68+
rev: v1.1.389
6969
hooks:
7070
- id: pyright

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Pymatgen (Python Materials Genomics) is a robust, open-source Python
2121
library for materials analysis. These are some of the main features:
2222

2323
1. Highly flexible classes for the representation of `Element`, `Site`, `Molecule` and `Structure` objects.
24-
2. Extensive input/output support, including support for [VASP](https://cms.mpi.univie.ac.at/vasp), [ABINIT](https://abinit.org), [CIF](https://wikipedia.org/wiki/Crystallographic_Information_File), [Gaussian](https://gaussian.com), [XYZ](https://wikipedia.org/wiki/XYZ_file_format), and many other file formats.
24+
2. Extensive input/output support, including support for [VASP](https://www.vasp.at/), [ABINIT](https://abinit.github.io/abinit_web/), [CIF](https://wikipedia.org/wiki/Crystallographic_Information_File), [Gaussian](https://gaussian.com), [XYZ](https://wikipedia.org/wiki/XYZ_file_format), and many other file formats.
2525
3. Powerful analysis tools, including generation of phase diagrams, Pourbaix diagrams, diffusion analyses, reactions, etc.
2626
4. Electronic structure analyses, such as density of states and band structure.
2727
5. Integration with the [Materials Project] REST API.

dev_scripts/potcar_scrambler.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ def generate_fake_potcar_libraries() -> None:
164164
zpath(f"{func_dir}/{psp_name}/POTCAR"),
165165
]
166166
if not any(map(os.path.isfile, paths_to_try)):
167-
warnings.warn(f"Could not find {psp_name} in {paths_to_try}")
167+
warnings.warn(f"Could not find {psp_name} in {paths_to_try}", stacklevel=2)
168168
for potcar_path in paths_to_try:
169169
if os.path.isfile(potcar_path):
170170
os.makedirs(rebase_dir, exist_ok=True)

pyproject.toml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,7 @@ Issues = "https://github.com/materialsproject/pymatgen/issues"
8787
Pypi = "https://pypi.org/project/pymatgen"
8888

8989
[project.optional-dependencies]
90-
# PR4128: netcdf4 1.7.[0/1] yanked, 1.7.1.post[1/2]/1.7.2 cause CI error
91-
abinit = ["netcdf4>=1.6.5,!=1.7.1.post1,!=1.7.1.post2,!=1.7.2"]
90+
abinit = ["netcdf4>=1.7.2"]
9291
ase = ["ase>=3.23.0"]
9392
ci = ["pytest-cov>=4", "pytest-split>=0.8", "pytest>=8"]
9493
docs = ["invoke", "sphinx", "sphinx_markdown_builder", "sphinx_rtd_theme"]
@@ -193,7 +192,6 @@ ignore = [
193192

194193
# Single rules
195194
"B023", # Function definition does not bind loop variable
196-
"B028", # No explicit stacklevel keyword argument found
197195
"B904", # Within an except clause, raise exceptions with ...
198196
"C408", # unnecessary-collection-call
199197
"D105", # Missing docstring in magic method

src/pymatgen/alchemy/materials.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ def to_snl(self, authors: list[str], **kwargs) -> StructureNL:
362362
StructureNL: The generated StructureNL object.
363363
"""
364364
if self.other_parameters:
365-
warn("Data in TransformedStructure.other_parameters discarded during type conversion to SNL")
365+
warn("Data in TransformedStructure.other_parameters discarded during type conversion to SNL", stacklevel=2)
366366
history = []
367367
for hist in self.history:
368368
snl_metadata = hist.pop("_snl", {})

src/pymatgen/analysis/bond_dissociation.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,8 @@ def __init__(
107107
if multibreak:
108108
warnings.warn(
109109
"Breaking pairs of ring bonds. WARNING: Structure changes much more likely, meaning dissociation values"
110-
" are less reliable! This is a bad idea!"
110+
" are less reliable! This is a bad idea!",
111+
stacklevel=2,
111112
)
112113
self.bond_pairs = []
113114
for ii, bond in enumerate(self.ring_bonds, start=1):
@@ -164,7 +165,8 @@ def fragment_and_process(self, bonds):
164165
warnings.warn(
165166
f"Missing ring opening fragment resulting from the breakage of {specie[bonds[0][0]]} "
166167
f"{specie[bonds[0][1]]} bond {bonds[0][0]} {bonds[0][1]} which would yield a "
167-
f"molecule with this SMILES string: {smiles}"
168+
f"molecule with this SMILES string: {smiles}",
169+
stacklevel=2,
168170
)
169171
elif len(good_entries) == 1:
170172
# If we have only one good entry, format it and add it to the list that will eventually return
@@ -212,14 +214,14 @@ def fragment_and_process(self, bonds):
212214
smiles = pb_mol.write("smi").split()[0]
213215
for charge in self.expected_charges:
214216
if charge not in frag1_charges_found:
215-
warnings.warn(f"Missing {charge=} for fragment {smiles}")
217+
warnings.warn(f"Missing {charge=} for fragment {smiles}", stacklevel=2)
216218
if len(frag2_charges_found) < len(self.expected_charges):
217219
bb = BabelMolAdaptor(fragments[1].molecule)
218220
pb_mol = bb.pybel_mol
219221
smiles = pb_mol.write("smi").split()[0]
220222
for charge in self.expected_charges:
221223
if charge not in frag2_charges_found:
222-
warnings.warn(f"Missing {charge=} for fragment {smiles}")
224+
warnings.warn(f"Missing {charge=} for fragment {smiles}", stacklevel=2)
223225
# Now we attempt to pair fragments with the right total charge, starting with only fragments with no
224226
# structural change:
225227
for frag1 in frag1_entries[0]: # 0 -> no structural change

src/pymatgen/analysis/chemenv/coordination_environments/coordination_geometry_finder.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,9 @@ def points_wcs_csc(self, permutation=None):
218218
"""
219219
if permutation is None:
220220
return self._points_wcs_csc
221-
return np.concatenate((self._points_wcs_csc[:1], self._points_wocs_csc.take(permutation, axis=0)))
221+
return np.concatenate(
222+
(self._points_wcs_csc[:1], self._points_wocs_csc.take(np.array(permutation, dtype=np.intp), axis=0))
223+
)
222224

223225
def points_wocs_csc(self, permutation=None):
224226
"""
@@ -227,7 +229,7 @@ def points_wocs_csc(self, permutation=None):
227229
"""
228230
if permutation is None:
229231
return self._points_wocs_csc
230-
return self._points_wocs_csc.take(permutation, axis=0)
232+
return self._points_wocs_csc.take(np.array(permutation, dtype=np.intp), axis=0)
231233

232234
def points_wcs_ctwcc(self, permutation=None):
233235
"""
@@ -239,7 +241,7 @@ def points_wcs_ctwcc(self, permutation=None):
239241
return np.concatenate(
240242
(
241243
self._points_wcs_ctwcc[:1],
242-
self._points_wocs_ctwcc.take(permutation, axis=0),
244+
self._points_wocs_ctwcc.take(np.array(permutation, dtype=np.intp), axis=0),
243245
)
244246
)
245247

@@ -250,7 +252,7 @@ def points_wocs_ctwcc(self, permutation=None):
250252
"""
251253
if permutation is None:
252254
return self._points_wocs_ctwcc
253-
return self._points_wocs_ctwcc.take(permutation, axis=0)
255+
return self._points_wocs_ctwcc.take(np.array(permutation, dtype=np.intp), axis=0)
254256

255257
def points_wcs_ctwocc(self, permutation=None):
256258
"""
@@ -262,7 +264,7 @@ def points_wcs_ctwocc(self, permutation=None):
262264
return np.concatenate(
263265
(
264266
self._points_wcs_ctwocc[:1],
265-
self._points_wocs_ctwocc.take(permutation, axis=0),
267+
self._points_wocs_ctwocc.take(np.array(permutation, dtype=np.intp), axis=0),
266268
)
267269
)
268270

@@ -273,7 +275,7 @@ def points_wocs_ctwocc(self, permutation=None):
273275
"""
274276
if permutation is None:
275277
return self._points_wocs_ctwocc
276-
return self._points_wocs_ctwocc.take(permutation, axis=0)
278+
return self._points_wocs_ctwocc.take(np.array(permutation, dtype=np.intp), axis=0)
277279

278280
@property
279281
def cn(self):
@@ -1976,6 +1978,7 @@ def _cg_csm_separation_plane_optim2(
19761978
stop_search = False
19771979
# TODO: do not do that several times ... also keep in memory
19781980
if sepplane.ordered_plane:
1981+
separation_indices = [arr.astype(np.intp) for arr in separation_indices]
19791982
inp = self.local_geometry.coords.take(separation_indices[1], axis=0)
19801983
if sepplane.ordered_point_groups[0]:
19811984
pp_s0 = self.local_geometry.coords.take(separation_indices[0], axis=0)
@@ -2051,10 +2054,7 @@ def coordination_geometry_symmetry_measures_fallback_random(
20512054
The symmetry measures for the given coordination geometry for each permutation investigated.
20522055
"""
20532056
if "NRANDOM" in kwargs:
2054-
warnings.warn(
2055-
"NRANDOM is deprecated, use n_random instead",
2056-
category=DeprecationWarning,
2057-
)
2057+
warnings.warn("NRANDOM is deprecated, use n_random instead", category=DeprecationWarning, stacklevel=2)
20582058
n_random = kwargs.pop("NRANDOM")
20592059
permutations_symmetry_measures = [None] * n_random
20602060
permutations = []

src/pymatgen/analysis/chempot_diagram.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,7 @@ def _get_3d_plot(
391391
if formulas_to_draw:
392392
for formula in formulas_to_draw:
393393
if formula not in domain_simplexes:
394-
warnings.warn(f"Specified formula to draw, {formula}, not found!")
394+
warnings.warn(f"Specified formula to draw, {formula}, not found!", stacklevel=2)
395395

396396
if draw_formula_lines:
397397
data.extend(self._get_3d_formula_lines(draw_domains, formula_colors))

src/pymatgen/analysis/elasticity/elastic.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def __new__(cls, input_array, check_rank=None, tol: float = 1e-4) -> Self:
6363
if obj.rank % 2 != 0:
6464
raise ValueError("ElasticTensor must have even rank")
6565
if not obj.is_voigt_symmetric(tol):
66-
warnings.warn("Input elastic tensor does not satisfy standard Voigt symmetries")
66+
warnings.warn("Input elastic tensor does not satisfy standard Voigt symmetries", stacklevel=2)
6767
return obj.view(cls)
6868

6969
@property
@@ -476,7 +476,8 @@ def from_pseudoinverse(cls, strains, stresses) -> Self:
476476
# convert the stress/strain to Nx6 arrays of voigt notation
477477
warnings.warn(
478478
"Pseudo-inverse fitting of Strain/Stress lists may yield "
479-
"questionable results from vasp data, use with caution."
479+
"questionable results from vasp data, use with caution.",
480+
stacklevel=2,
480481
)
481482
stresses = np.array([Stress(stress).voigt for stress in stresses])
482483
with warnings.catch_warnings():
@@ -505,7 +506,9 @@ def from_independent_strains(cls, strains, stresses, eq_stress=None, vasp=False,
505506
if not set(strain_states) <= set(ss_dict):
506507
raise ValueError(f"Missing independent strain states: {set(strain_states) - set(ss_dict)}")
507508
if len(set(ss_dict) - set(strain_states)) > 0:
508-
warnings.warn("Extra strain states in strain-stress pairs are neglected in independent strain fitting")
509+
warnings.warn(
510+
"Extra strain states in strain-stress pairs are neglected in independent strain fitting", stacklevel=2
511+
)
509512
c_ij = np.zeros((6, 6))
510513
for ii in range(6):
511514
strains = ss_dict[strain_states[ii]]["strains"]
@@ -916,7 +919,7 @@ def find_eq_stress(strains, stresses, tol: float = 1e-10):
916919
)
917920
eq_stress = eq_stress[0]
918921
else:
919-
warnings.warn("No eq state found, returning zero voigt stress")
922+
warnings.warn("No eq state found, returning zero voigt stress", stacklevel=2)
920923
eq_stress = Stress(np.zeros((3, 3)))
921924
return eq_stress
922925

src/pymatgen/analysis/ewald.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ def get_site_energy(self, site_index):
288288
self._initialized = True
289289

290290
if self._charged:
291-
warn("Per atom energies for charged structures not supported in EwaldSummation")
291+
warn("Per atom energies for charged structures not supported in EwaldSummation", stacklevel=2)
292292
return np.sum(self._recip[:, site_index]) + np.sum(self._real[:, site_index]) + self._point[site_index]
293293

294294
def _calc_ewald_terms(self):

src/pymatgen/analysis/gb/grain.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@
88
"Grain boundary analysis has been moved to pymatgen.core.interface."
99
"This stub is retained for backwards compatibility and will be removed Dec 31 2024.",
1010
DeprecationWarning,
11+
stacklevel=2,
1112
)

src/pymatgen/analysis/graphs.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ def add_edge(
383383
# edges if appropriate
384384
if to_jimage is None:
385385
# assume we want the closest site
386-
warnings.warn("Please specify to_jimage to be unambiguous, trying to automatically detect.")
386+
warnings.warn("Please specify to_jimage to be unambiguous, trying to automatically detect.", stacklevel=2)
387387
dist, to_jimage = self.structure[from_index].distance_and_image(self.structure[to_index])
388388
if dist == 0:
389389
# this will happen when from_index == to_index,
@@ -417,7 +417,7 @@ def add_edge(
417417
# this is a convention to avoid duplicate hops
418418
if to_index == from_index:
419419
if to_jimage == (0, 0, 0):
420-
warnings.warn("Tried to create a bond to itself, this doesn't make sense so was ignored.")
420+
warnings.warn("Tried to create a bond to itself, this doesn't make sense so was ignored.", stacklevel=2)
421421
return
422422

423423
# ensure that the first non-zero jimage index is positive
@@ -439,7 +439,8 @@ def add_edge(
439439
if warn_duplicates:
440440
warnings.warn(
441441
"Trying to add an edge that already exists from "
442-
f"site {from_index} to site {to_index} in {to_jimage}."
442+
f"site {from_index} to site {to_index} in {to_jimage}.",
443+
stacklevel=2,
443444
)
444445
return
445446

@@ -1826,7 +1827,9 @@ def add_edge(
18261827
# between two sites
18271828
existing_edge_data = self.graph.get_edge_data(from_index, to_index)
18281829
if existing_edge_data and warn_duplicates:
1829-
warnings.warn(f"Trying to add an edge that already exists from site {from_index} to site {to_index}.")
1830+
warnings.warn(
1831+
f"Trying to add an edge that already exists from site {from_index} to site {to_index}.", stacklevel=2
1832+
)
18301833
return
18311834

18321835
# generic container for additional edge properties,

src/pymatgen/analysis/interface_reactions.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -484,8 +484,10 @@ def _get_entry_energy(pd: PhaseDiagram, composition: Composition):
484484

485485
if not candidate:
486486
warnings.warn(
487-
f"The reactant {composition.reduced_formula} has no matching entry with negative formation"
488-
" energy, instead convex hull energy for this composition will be used for reaction energy calculation."
487+
f"The reactant {composition.reduced_formula} has no matching entry "
488+
"with negative formation energy, instead convex hull energy for "
489+
"this composition will be used for reaction energy calculation.",
490+
stacklevel=2,
489491
)
490492
return pd.get_hull_energy(composition)
491493
min_entry_energy = min(candidate)
@@ -545,8 +547,9 @@ def get_chempot_correction(cls, element: str, temp: float, pres: float): # code
545547
The correction of chemical potential in eV/atom of the gas
546548
phase at given temperature and pressure.
547549
"""
548-
if element not in ["O", "N", "Cl", "F", "H"]:
549-
warnings.warn(f"{element=} not one of valid options: ['O', 'N', 'Cl', 'F', 'H']")
550+
valid_elements = {"O", "N", "Cl", "F", "H"}
551+
if element not in valid_elements:
552+
warnings.warn(f"{element=} not one of valid options: {valid_elements}", stacklevel=2)
550553
return 0
551554

552555
std_temp = 298.15

src/pymatgen/analysis/local_env.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4025,7 +4025,8 @@ def get_nn_data(self, structure: Structure, n: int, length=None):
40254025
warnings.warn(
40264026
"CrystalNN: cannot locate an appropriate radius, "
40274027
"covalent or atomic radii will be used, this can lead "
4028-
"to non-optimal results."
4028+
"to non-optimal results.",
4029+
stacklevel=2,
40294030
)
40304031
diameter = _get_default_radius(structure[n]) + _get_default_radius(entry["site"])
40314032

@@ -4231,7 +4232,8 @@ def _get_radius(site):
42314232
else:
42324233
warnings.warn(
42334234
"No oxidation states specified on sites! For better results, set "
4234-
"the site oxidation states in the structure."
4235+
"the site oxidation states in the structure.",
4236+
stacklevel=2,
42354237
)
42364238
return 0
42374239

0 commit comments

Comments
 (0)