Skip to content

Commit

Permalink
Merge branch 'materialsproject:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
soge8904 authored Oct 16, 2024
2 parents 7775f1d + ec043b1 commit 51ef781
Show file tree
Hide file tree
Showing 32 changed files with 682,816 additions and 89 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
run: conda install -c conda-forge openbabel

- name: Install dependencies
run: uv pip install numpy==1.26.4 ; uv pip install -e '.[dev]' --system
run: uv pip install -e '.[dev]' --system

- name: pytest
env:
Expand Down
12 changes: 6 additions & 6 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,29 @@ ci:

repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.5.0
rev: v0.6.9
hooks:
- id: ruff
args: [ --fix, --unsafe-fixes ]
- id: ruff-format

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
rev: v5.0.0
hooks:
- id: check-yaml
- id: end-of-file-fixer
- id: trailing-whitespace

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

- repo: https://github.com/codespell-project/codespell
rev: v2.3.0
hooks:
- id: codespell
stages: [ commit, commit-msg ]
stages: [ commit-msg ]
exclude_types: [ html ]
additional_dependencies: [ tomli ] # needed to read pyproject.toml below py3.11

Expand All @@ -47,7 +47,7 @@ repos:
- id: blacken-docs

- repo: https://github.com/igorshubovych/markdownlint-cli
rev: v0.41.0
rev: v0.42.0
hooks:
- id: markdownlint
# MD013: line too long
Expand All @@ -64,6 +64,6 @@ repos:
args: [ --drop-empty-cells, --keep-output ]

- repo: https://github.com/RobertCraigie/pyright-python
rev: v1.1.369
rev: v1.1.383
hooks:
- id: pyright
14 changes: 14 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@ nav_order: 2

# Change Log

## 2024.10.16
* Add a update_incar option in VaspJob which updates parameters from a previous vasprun.xml.

## 2024.10.15
* Bug fix for pip installation.

## 2024.10.14
* PR #342 from @esoteric-ephemera (#342)
Minor update to the logic of the `auto_nbands` check for `VaspErrorHandler`. This check sees if the number of bands has been updated by VASP, and currently it only checks to see if that updated number is very large.
However, there are cases where the user specifies an NBANDS that is incompatible with their parallelization settings, as NBANDS must be divisible by $(\mathrm{ranks}) / (\mathrm{KPAR} \times \mathrm{NCORE})$. In these cases, VASP increases the number of bands to ensure the calculation can still proceed. This can happen in MP's band structure workflows with uniform $k$-point densities.
However, since the current `auto_nbands` handler applies no corrections to the job, these otherwise successful runs are killed.
This PR adds logic to ensure that the calculation is rerun with a higher number of bands appropriate to the parallelization setting. This is kinda redundant, since VASP already does this. But I think it has to occur this way because `VaspErrorHandler` is monitoring the job and flags it for an `auto_nbands` error.
Another implementation concern: it's generally safer to decrease the number of bands since this requires a lower energy cutoff to converge each band. It might be safer to decrease NBANDS as a fix

## 2024.6.24
- Improved handling of ISMEAR for NKPT<4 (@Andrew-S-Rosen, @esoteric-ephemera)

Expand Down
32 changes: 16 additions & 16 deletions docs/custodian.gaussian.handlers.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ nav_exclude: true

This module implements error handlers for Gaussian runs.

### *class* custodian.gaussian.handlers.GaussianErrorHandler(input_file: str, output_file: str, stderr_file: str = 'stderr.txt', cart_coords: bool = True, scf_max_cycles: int = 100, opt_max_cycles: int = 100, job_type: str = 'normal', lower_functional: str | None = None, lower_basis_set: str | None = None, prefix: str = 'error', check_convergence: bool = True)
## *class* custodian.gaussian.handlers.GaussianErrorHandler(input_file: str, output_file: str, stderr_file: str = stderr.txt, cart_coords: bool = True, scf_max_cycles: int = 100, opt_max_cycles: int = 100, job_type: str = normal, lower_functional: str | None = None, lower_basis_set: str | None = None, prefix: str = error, check_convergence: bool = True)

Bases: `ErrorHandler`

Expand Down Expand Up @@ -41,19 +41,19 @@ Initialize the GaussianErrorHandler class.
be monitored and plotted (convergence criteria versus cycle number) and
saved to a file called ‘convergence.png’.

#### GRID_NAMES *= ('finegrid', 'fine', 'superfinegrid', 'superfine', 'coarsegrid', 'coarse', 'sg1grid', 'sg1', 'pass0grid', 'pass0')*
### GRID_NAMES *= (finegrid’, ‘fine’, ‘superfinegrid’, ‘superfine’, ‘coarsegrid’, ‘coarse’, ‘sg1grid’, ‘sg1’, ‘pass0grid’, ‘pass0)*

#### MEM_UNITS *= ('kb', 'mb', 'gb', 'tb', 'kw', 'mw', 'gw', 'tw')*
### MEM_UNITS *= (‘kb’, ‘mb’, ‘gb’, ‘tb’, ‘kw’, ‘mw’, ‘gw’, ‘tw’)*

#### activate_better_guess *= False*
### activate_better_guess *= False*

#### check(directory: str = './')
### check(directory: str = ‘./’)

Check for errors in the Gaussian output file.

#### conv_criteria*: ClassVar* *= {'max_disp': re.compile('\\\\s+(Maximum Displacement)\\\\s+(-?\\\\d+.?\\\\d\*|.\*)\\\\s+(-?\\\\d+.?\\\\d\*)'), 'max_force': re.compile('\\\\s+(Maximum Force)\\\\s+(-?\\\\d+.?\\\\d\*|.\*)\\\\s+(-?\\\\d+.?\\\\d\*)'), 'rms_disp': re.compile('\\\\s+(RMS {5}Displacement)\\\\s+(-?\\\\d+.?\\\\d\*|.\*)\\\\s+(-?\\\\d+.?\\\\d\*)'), 'rms_force': re.compile('\\\\s+(RMS {5}Force)\\\\s+(-?\\\\d+.?\\\\d\*|.\*)\\\\s+(-?\\\\d+.?\\\\d\*)')}*
### conv_criteria\*: ClassVar\* *= {max_disp: re.compile(\\s+(Maximum Displacement)\\s+(-?\\d+.?\\d\*|.\*)\\s+(-?\\d+.?\\d\*)), max_force: re.compile(\\s+(Maximum Force)\\s+(-?\\d+.?\\d\*|.\*)\\s+(-?\\d+.?\\d\*)), rms_disp: re.compile(\\s+(RMS {5}Displacement)\\s+(-?\\d+.?\\d\*|.\*)\\s+(-?\\d+.?\\d\*)), rms_force: re.compile(\\s+(RMS {5}Force)\\s+(-?\\d+.?\\d\*|.\*)\\s+(-?\\d+.?\\d\*))}*

#### *static* convert_mem(mem: float, unit: str)
### *static* convert_mem(mem: float, unit: str)

Convert memory size between different units to megabytes (MB).

Expand All @@ -67,19 +67,19 @@ Convert memory size between different units to megabytes (MB).
* **Return type:**
float

#### correct(directory: str = './')
### correct(directory: str = ‘./’)

Perform necessary actions to correct the errors in the Gaussian output.

#### error_defs*: ClassVar* *= {'A syntax error was detected in the input line.': 'syntax', 'Atom specifications unexpectedly found in input stream.': 'found_coords', 'Bad file opened by FileIO': 'bad_file', 'Convergence failure': 'scf_convergence', 'End of file in ZSymb': 'zmatrix', 'End of file reading connectivity.': 'coords', 'Error in internal coordinate system': 'internal_coords', 'FileIO operation on non-existent file.': 'missing_file', 'FormBX had a problem': 'linear_bend', 'Inv3 failed in PCMMkU': 'solute_solvent_surface', 'Linear angle in Tors.': 'linear_bend', 'No data on chk file.': 'empty_file', 'Optimization stopped': 'opt_steps', 'Out-of-memory error in routine': 'insufficient_mem', 'The combination of multiplicity ([0-9]+) and \\\\s+? ([0-9]+) electrons is impossible.': 'charge', 'There are no atoms in this input structure !': 'missing_mol', 'Z-matrix optimization but no Z-matrix variables.': 'coord_inputs'}*
### error_defs\*: ClassVar\* *= {A syntax error was detected in the input line.’: ‘syntax’, ‘Atom specifications unexpectedly found in input stream.’: ‘found_coords’, ‘Bad file opened by FileIO’: ‘bad_file’, ‘Convergence failure’: ‘scf_convergence’, ‘End of file in ZSymb’: ‘zmatrix’, ‘End of file reading connectivity.’: ‘coords’, ‘Error in internal coordinate system’: ‘internal_coords’, ‘FileIO operation on non-existent file.’: ‘missing_file’, ‘FormBX had a problem’: ‘linear_bend’, ‘Inv3 failed in PCMMkU’: ‘solute_solvent_surface’, ‘Linear angle in Tors.’: ‘linear_bend’, ‘No data on chk file.’: ‘empty_file’, ‘Optimization stopped’: ‘opt_steps’, ‘Out-of-memory error in routine’: ‘insufficient_mem’, ‘The combination of multiplicity ([0-9]+) and \\s+? ([0-9]+) electrons is impossible.’: ‘charge’, ‘There are no atoms in this input structure !’: ‘missing_mol’, ‘Z-matrix optimization but no Z-matrix variables.’: ‘coord_inputs}*

#### error_patt *= re.compile('Optimization stopped|Convergence failure|FormBX had a problem|Linear angle in Tors.|Inv3 failed in PCMMkU|Error in internal coordinate system|End of file in ZSymb|There are no atoms in this input str)*
### error_patt *= re.compile(Optimization stopped|Convergence failure|FormBX had a problem|Linear angle in Tors.|Inv3 failed in PCMMkU|Error in internal coordinate system|End of file in ZSymb|There are no atoms in this input str)*

#### grid_patt *= re.compile('(-?\\\\d{5})')*
### grid_patt *= re.compile((-?\\d{5}))*

#### recom_mem_patt *= re.compile('Use %mem=([0-9]+)MW to provide the minimum amount of memory required to complete this step.')*
### recom_mem_patt *= re.compile(Use %mem=([0-9]+)MW to provide the minimum amount of memory required to complete this step.)*

### *class* custodian.gaussian.handlers.WallTimeErrorHandler(wall_time: int, buffer_time: int, input_file: str, output_file: str, stderr_file: str = 'stderr.txt', prefix: str = 'error')
## *class* custodian.gaussian.handlers.WallTimeErrorHandler(wall_time: int, buffer_time: int, input_file: str, output_file: str, stderr_file: str = stderr.txt, prefix: str = error)

Bases: `ErrorHandler`

Expand All @@ -102,15 +102,15 @@ Initialize the WalTimeErrorHandler class.
which means a series of error.1.tar.gz, error.2.tar.gz, … will be
generated.

#### check(directory: str = './')
### check(directory: str = ‘./’)

Check if the job is nearing the walltime. If so, return True, else False.

#### correct(directory: str = './')
### correct(directory: str = ‘./’)

Perform the corrections.

#### is_monitor*: bool* *= True*
### is_monitor\*: bool\* *= True*

This class property indicates whether the error handler is a monitor,
i.e., a handler that monitors a job as it is running. If a
Expand Down
12 changes: 6 additions & 6 deletions docs/custodian.gaussian.jobs.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ nav_exclude: true

This module implements basic kinds of jobs for Gaussian runs.

### *class* custodian.gaussian.jobs.GaussianJob(gaussian_cmd: str, input_file: str, output_file: str, stderr_file: str = 'stderr.txt', suffix: str = '', backup: bool = True)
## *class* custodian.gaussian.jobs.GaussianJob(gaussian_cmd: str, input_file: str, output_file: str, stderr_file: str = stderr.txt, suffix: str = ‘’, backup: bool = True)

Bases: `Job`

Expand All @@ -26,7 +26,7 @@ A basic Gaussian job.
* **backup** (*bool*) – Whether to backup the input file. If True, the input will be
copied with a “.orig” appended to the name. Defaults to True.

#### *classmethod* generate_better_guess(gaussian_cmd: str, input_file: str, output_file: str, stderr_file: str = 'stderr.txt', backup: bool = True, cart_coords: bool = True, directory: str = './')
### *classmethod* generate_better_guess(gaussian_cmd: str, input_file: str, output_file: str, stderr_file: str = stderr.txt, backup: bool = True, cart_coords: bool = True, directory: str = ‘./’)

Generate a better initial guess for a Gaussian calculation (optimization or
SCF run). This is done by running the job at a lower level of theory
Expand All @@ -46,15 +46,15 @@ generated by the previous job.
* **Yields:**
*GaussianJob* – The Gaussian job instance.

#### postprocess(directory: str = './')
### postprocess(directory: str = ‘./’)

Perform any postprocessing of the Gaussian run. This includes making a copy
of the input and output file if a suffix is specified.

* **Parameters:**
**directory** (*str*) – Directory where the job was run. Defaults to ‘./’.

#### run(directory: str = './')
### run(directory: str = ‘./’)

Perform the actual Gaussian run.

Expand All @@ -65,15 +65,15 @@ Perform the actual Gaussian run.
* **Return type:**
subprocess.Popen

#### setup(directory: str = './')
### setup(directory: str = ‘./’)

Perform initial setup for the job, i.e., make a backup of the input file if
requested.

* **Parameters:**
**directory** (*str*) – Directory where the job will be run. Defaults to ‘./’.

#### terminate(directory: str = './')
### terminate(directory: str = ‘./’)

Terminate the Gaussian job.

Expand Down
1 change: 0 additions & 1 deletion docs/custodian.gaussian.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ nav_exclude: true

This package implements various Gaussian Jobs and Error Handlers.


* [custodian.gaussian.handlers module](custodian.gaussian.handlers.md)
* [`GaussianErrorHandler`](custodian.gaussian.handlers.md#custodian.gaussian.handlers.GaussianErrorHandler)
* [`GaussianErrorHandler.GRID_NAMES`](custodian.gaussian.handlers.md#custodian.gaussian.handlers.GaussianErrorHandler.GRID_NAMES)
Expand Down
41 changes: 21 additions & 20 deletions docs/custodian.vasp.utils.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,30 @@ nav_exclude: true

Utility methods for VASP error handlers.

### custodian.vasp.utils.increase_k_point_density(kpoints: Kpoints | dict | float, structure: Structure, factor: float = 0.1, max_inc: int = 500, min_kpoints: int = 1, force_gamma: bool = True)
## custodian.vasp.utils.increase_k_point_density(kpoints: Kpoints | dict | float, structure: Structure, factor: float = 0.1, max_inc: int = 500, min_kpoints: int = 1, force_gamma: bool = True)

Inputs:
: kpoints (Kpoints, dict, float, int) :
: If a dict or Kpoints object: original Kpoints used in the calculation
If a float: the original KSPACING used in the calculation
<br/>
structure (Structure) : associated structure
factor (float) : factor used to increase k-point density.
<br/>
> The first increase uses approximately (1 + factor) higher k-point density.
> The second increase: ~ (1 + 2\*factor) higher k-kpoint density, etc.
max_inc (int)
: before giving up
<br/>
min_kpoints (int): The minimum permitted number of k-points.
: Can be useful if using the tetrahedron method, where
at least 4 k-points are needed.
<br/>
force_gamma (bool) = True: whether to use Gamma-centered or
: Monkhorst-Pack grids
: If a dict or Kpoints object: original Kpoints used in the calculation
If a float: the original KSPACING used in the calculation
<br/>
structure (Structure) : associated structure
factor (float) : factor used to increase k-point density.
<br/>

> The first increase uses approximately (1 + factor) higher k-point density.
> The second increase: ~ (1 + 2\*factor) higher k-kpoint density, etc.
> max_inc (int)
> : before giving up
> <br/>
> min_kpoints (int): The minimum permitted number of k-points.
> : Can be useful if using the tetrahedron method, where
> at least 4 k-points are needed.
> <br/>
> force_gamma (bool) = True: whether to use Gamma-centered or
> : Monkhorst-Pack grids
Outputs:
: dict :
: The new Kpoints object / KSPACING consistent with constraints.
If an empty dict, no new k-point mesh could be found.
: The new Kpoints object / KSPACING consistent with constraints.
If an empty dict, no new k-point mesh could be found.
12 changes: 7 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "custodian"
version = "2024.6.24"
version = "2024.10.16"
description = "A simple JIT job management framework in Python."
authors = [
{ name = "Janosh Riebesell", email = "janosh.riebesell@gmail.com" },
Expand All @@ -19,21 +19,20 @@ maintainers = [{ name = "Janosh Riebesell" }, { name = "Shyue Ping Ong" }]
readme = "README.md"
keywords = ["jit", "job", "just-in-time", "management", "vasp", "nwchem", "qchem"]
classifiers = [
"Development Status :: 4 - Beta",
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Science/Research",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.9",
"Topic :: Scientific/Engineering :: Chemistry",
"Topic :: Scientific/Engineering :: Physics",
"Topic :: Software Development :: Libraries :: Python Modules",
]
license = { file = "LICENSE" }
requires-python = ">=3.9"
requires-python = ">=3.10"

dependencies = ["monty>=2.0.6", "psutil", "ruamel.yaml>=0.15.6"]

Expand All @@ -58,7 +57,7 @@ Package = "https://pypi.org/project/custodian"

[tool.setuptools.packages.find]
where = ["src"]
include = ["custodian"]
include = ["custodian*"]

[tool.ruff]
target-version = "py311"
Expand Down Expand Up @@ -163,3 +162,6 @@ reportMissingImports = false
reportMissingModuleSource = false
reportInvalidTypeForm = false
exclude = ["**/tests"]

[tool.setuptools.package-data]
custodian = ["py.typed"]
Empty file added src/custodian/py.typed
Empty file.
19 changes: 19 additions & 0 deletions src/custodian/vasp/jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ def __init__(
gamma_vasp_cmd=None,
copy_magmom=False,
auto_continue=False,
update_incar=False,
) -> None:
"""
This constructor is necessarily complex due to the need for
Expand Down Expand Up @@ -136,6 +137,12 @@ def __init__(
if a STOPCAR is present. This is very useful if using the
wall-time handler which will write a read-only STOPCAR to
prevent VASP from deleting it once it finishes
update_incar (bool): Whether to update INCAR settings from updated settings
in vasprun.xml. This is particularly useful in certain calculatons where VASP
automatically sets certain parameters, e.g., NBANDS. Only parameters that are
already present in the INCAR will be updated, i.e., no new parameters will be
added even if they are in the final vasprun.xml. Note that settings_override take
precedence over updated params.
"""
self.vasp_cmd = tuple(vasp_cmd)
self.output_file = output_file
Expand All @@ -149,6 +156,7 @@ def __init__(
self.gamma_vasp_cmd = tuple(gamma_vasp_cmd) if gamma_vasp_cmd else None
self.copy_magmom = copy_magmom
self.auto_continue = auto_continue
self.update_incar = update_incar

if SENTRY_DSN:
# if using Sentry logging, add specific VASP executable to scope
Expand Down Expand Up @@ -228,6 +236,17 @@ def setup(self, directory="./") -> None:
actions = self.auto_continue
dumpfn({"actions": actions}, os.path.join(directory, "continue.json"))

if self.update_incar:
try:
vasprun = Vasprun(os.path.join(directory, "vasprun.xml"))
params = vasprun.parameters
incar = Incar.from_file(os.path.join(directory, "INCAR"))
for k, v in incar.items():
incar[k] = params.get(k, v)
incar.write_file(os.path.join(directory, "INCAR"))
except Exception as ex:
logger.error(f"Unable to update INCAR with params from vasprun.xml. {ex}")

if self.settings_override is not None:
VaspModder(directory=directory).apply_actions(self.settings_override)

Expand Down
3 changes: 2 additions & 1 deletion tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@
from glob import glob

import requests
from custodian import __version__ as CURRENT_VER
from invoke import task
from monty.os import cd

from custodian import __version__ as CURRENT_VER

NEW_VER = datetime.datetime.now(tz=datetime.UTC).strftime("%Y.%-m.%-d")


Expand Down
1 change: 1 addition & 0 deletions tests/ansible/test_interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from typing import Any

import pytest

from custodian.ansible.actions import FileActions
from custodian.ansible.interpreter import Modder

Expand Down
Loading

0 comments on commit 51ef781

Please sign in to comment.