Skip to content

Commit 720fdf8

Browse files
Add multiwfn QTAIM parsing capabilities (#3926)
* Initial commit; thank you, Santiago! * Refactoring to clean up parsing; add rings and cages * More progress * Almost done with first draft; just need to put all of the pieces together * Some cleaning up; some work still to be done here * First draft, done * First steps towards tests * Progress on tests; some small bugfixes * More tests * Finished! * Remove unnecessary files * Trying to fight linters and type checkers and all that nonsense * pre-commit auto-fixes * Please, ruff, be kind * Please no more linting, please no more linting * pre-commit auto-fixes * (hopefully) just one more mypy issue * Whoops * Opinionated linters hate Union and Optional * pre-commit auto-fixes * Someday, I will meet the creators of mypy, and they will feel my rage * Small type change suggested by @DanielYang59 * pre-commit auto-fixes * Added wavefunction output as a feature of Q-Chem sets * Add back in qtaim-based bond definition (rather than distance-based definition); seems to fail for metals, but might be better elsewhere * Somehow, the linter was mad at me for things that I never touched. Injustice! * Added a third way to define bonds * mypy, of course --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 5256fce commit 720fdf8

File tree

15 files changed

+21014
-3
lines changed

15 files changed

+21014
-3
lines changed

src/pymatgen/core/structure.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1874,7 +1874,7 @@ def get_symmetric_neighbor_list(
18741874
redundant.append(jdx)
18751875

18761876
# Delete the redundant neighbors
1877-
m = ~np.in1d(np.arange(len(bonds[0])), redundant)
1877+
m = ~np.isin(np.arange(len(bonds[0])), redundant)
18781878
idcs_dist = np.argsort(bonds[3][m])
18791879
bonds = (bonds[0][m][idcs_dist], bonds[1][m][idcs_dist], bonds[2][m][idcs_dist], bonds[3][m][idcs_dist])
18801880

src/pymatgen/io/multiwfn.py

Lines changed: 546 additions & 0 deletions
Large diffs are not rendered by default.

src/pymatgen/io/qchem/sets.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ def __init__(
150150
max_scf_cycles: int = 100,
151151
geom_opt_max_cycles: int = 200,
152152
plot_cubes: bool = False,
153+
output_wavefunction: bool = False,
153154
nbo_params: dict | None = None,
154155
geom_opt: dict | None = None,
155156
cdft_constraints: list[list[dict]] | None = None,
@@ -229,6 +230,8 @@ def __init__(
229230
max_scf_cycles (int): Maximum number of SCF iterations. (Default: 100)
230231
geom_opt_max_cycles (int): Maximum number of geometry optimization iterations. (Default: 200)
231232
plot_cubes (bool): Whether to write CUBE files of the electron density. (Default: False)
233+
output_wavefunction (bool): Whether to write a wavefunction (*.wfn) file of the electron density
234+
(Default: False)
232235
nbo_params (dict): A dict containing the desired NBO params. Note that a key:value pair of
233236
"version":7 will trigger NBO7 analysis. Otherwise, NBO5 analysis will be performed,
234237
including if an empty dict is passed. Besides a key of "version", all other key:value
@@ -368,6 +371,7 @@ def __init__(
368371
self.max_scf_cycles = max_scf_cycles
369372
self.geom_opt_max_cycles = geom_opt_max_cycles
370373
self.plot_cubes = plot_cubes
374+
self.output_wavefunction = output_wavefunction
371375
self.nbo_params = nbo_params
372376
self.geom_opt = geom_opt
373377
self.cdft_constraints = cdft_constraints
@@ -430,6 +434,10 @@ def __init__(
430434
if self.job_type.lower() in ["opt", "ts", "pes_scan"]:
431435
rem["geom_opt_max_cycles"] = str(self.geom_opt_max_cycles)
432436

437+
# To keep things simpler on the analysis side, don't give user option to change *.wfn file name
438+
if self.output_wavefunction:
439+
rem["write_wfn"] = "wavefunction"
440+
433441
solvent_def = 0
434442
for a in [self.pcm_dielectric, self.isosvp_dielectric, self.smd_solvent, self.cmirs_solvent]:
435443
if a is not None:
@@ -644,6 +652,7 @@ def __init__(
644652
custom_smd: str | None = None,
645653
max_scf_cycles: int = 100,
646654
plot_cubes: bool = False,
655+
output_wavefunction: bool = False,
647656
nbo_params: dict | None = None,
648657
vdw_mode: Literal["atomic", "sequential"] = "atomic",
649658
cdft_constraints: list[list[dict]] | None = None,
@@ -713,6 +722,8 @@ def __init__(
713722
Refer to the QChem manual for further details.
714723
max_scf_cycles (int): Maximum number of SCF iterations. (Default: 100)
715724
plot_cubes (bool): Whether to write CUBE files of the electron density. (Default: False)
725+
output_wavefunction (bool): Whether to write a wavefunction (*.wfn) file of the electron density
726+
(Default: False)
716727
cdft_constraints (list of lists of dicts):
717728
A list of lists of dictionaries, where each dictionary represents a charge
718729
constraint in the cdft section of the QChem input file.
@@ -842,6 +853,7 @@ def __init__(
842853
qchem_version=qchem_version,
843854
max_scf_cycles=self.max_scf_cycles,
844855
plot_cubes=plot_cubes,
856+
output_wavefunction=output_wavefunction,
845857
nbo_params=nbo_params,
846858
vdw_mode=vdw_mode,
847859
cdft_constraints=cdft_constraints,
@@ -868,6 +880,7 @@ def __init__(
868880
custom_smd: str | None = None,
869881
max_scf_cycles: int = 100,
870882
plot_cubes: bool = False,
883+
output_wavefunction: bool = False,
871884
nbo_params: dict | None = None,
872885
opt_variables: dict[str, list] | None = None,
873886
geom_opt_max_cycles: int = 200,
@@ -940,6 +953,8 @@ def __init__(
940953
explicitly requested by passing in a dictionary (empty or otherwise) for this input parameter.
941954
(Default: False)
942955
plot_cubes (bool): Whether to write CUBE files of the electron density. (Default: False)
956+
output_wavefunction (bool): Whether to write a wavefunction (*.wfn) file of the electron density
957+
(Default: False)
943958
vdw_mode ('atomic' | 'sequential'): Method of specifying custom van der Waals radii. Applies
944959
only if you are using overwrite_inputs to add a $van_der_waals section to the input.
945960
In 'atomic' mode (default), dict keys represent the atomic number associated with each
@@ -1053,6 +1068,7 @@ def __init__(
10531068
max_scf_cycles=self.max_scf_cycles,
10541069
geom_opt_max_cycles=self.geom_opt_max_cycles,
10551070
plot_cubes=plot_cubes,
1071+
output_wavefunction=output_wavefunction,
10561072
nbo_params=nbo_params,
10571073
geom_opt=geom_opt,
10581074
cdft_constraints=cdft_constraints,
@@ -1077,6 +1093,7 @@ def __init__(
10771093
custom_smd: str | None = None,
10781094
max_scf_cycles: int = 100,
10791095
plot_cubes: bool = False,
1096+
output_wavefunction: bool = False,
10801097
nbo_params: dict | None = None,
10811098
opt_variables: dict[str, list] | None = None,
10821099
geom_opt_max_cycles: int = 200,
@@ -1146,6 +1163,8 @@ def __init__(
11461163
explicitly requested by passing in a dictionary (empty or otherwise) for this input parameter.
11471164
(Default: False)
11481165
plot_cubes (bool): Whether to write CUBE files of the electron density. (Default: False)
1166+
output_wavefunction (bool): Whether to write a wavefunction (*.wfn) file of the electron density
1167+
(Default: False)
11491168
overwrite_inputs (dict): Dictionary of QChem input sections to add or overwrite variables.
11501169
The currently available sections (keys) are rem, pcm,
11511170
solvent, smx, opt, scan, van_der_waals, and plots. The value of each key is a
@@ -1187,6 +1206,7 @@ def __init__(
11871206
max_scf_cycles=self.max_scf_cycles,
11881207
geom_opt_max_cycles=self.geom_opt_max_cycles,
11891208
plot_cubes=plot_cubes,
1209+
output_wavefunction=output_wavefunction,
11901210
nbo_params=nbo_params,
11911211
geom_opt=geom_opt,
11921212
overwrite_inputs=overwrite_inputs,
@@ -1211,6 +1231,7 @@ def __init__(
12111231
custom_smd: str | None = None,
12121232
max_scf_cycles: int = 100,
12131233
plot_cubes: bool = False,
1234+
output_wavefunction: bool = False,
12141235
nbo_params: dict | None = None,
12151236
vdw_mode: Literal["atomic", "sequential"] = "atomic",
12161237
cdft_constraints: list[list[dict]] | None = None,
@@ -1271,6 +1292,8 @@ def __init__(
12711292
Refer to the QChem manual for further details.
12721293
max_scf_cycles (int): Maximum number of SCF iterations. (Default: 100)
12731294
plot_cubes (bool): Whether to write CUBE files of the electron density. (Default: False)
1295+
output_wavefunction (bool): Whether to write a wavefunction (*.wfn) file of the electron density
1296+
(Default: False)
12741297
vdw_mode ('atomic' | 'sequential'): Method of specifying custom van der Waals radii. Applies
12751298
only if you are using overwrite_inputs to add a $van_der_waals section to the input.
12761299
In 'atomic' mode (default), dict keys represent the atomic number associated with each
@@ -1376,6 +1399,7 @@ def __init__(
13761399
qchem_version=qchem_version,
13771400
max_scf_cycles=self.max_scf_cycles,
13781401
plot_cubes=plot_cubes,
1402+
output_wavefunction=output_wavefunction,
13791403
nbo_params=nbo_params,
13801404
vdw_mode=vdw_mode,
13811405
cdft_constraints=cdft_constraints,
@@ -1400,6 +1424,7 @@ def __init__(
14001424
custom_smd: str | None = None,
14011425
max_scf_cycles: int = 100,
14021426
plot_cubes: bool = False,
1427+
output_wavefunction: bool = False,
14031428
nbo_params: dict | None = None,
14041429
vdw_mode: Literal["atomic", "sequential"] = "atomic",
14051430
cdft_constraints: list[list[dict]] | None = None,
@@ -1460,6 +1485,8 @@ def __init__(
14601485
Refer to the QChem manual for further details.
14611486
max_scf_cycles (int): Maximum number of SCF iterations. (Default: 100)
14621487
plot_cubes (bool): Whether to write CUBE files of the electron density. (Default: False)
1488+
output_wavefunction (bool): Whether to write a wavefunction (*.wfn) file of the electron density
1489+
(Default: False)
14631490
vdw_mode ('atomic' | 'sequential'): Method of specifying custom van der Waals radii. Applies
14641491
only if you are using overwrite_inputs to add a $van_der_waals section to the input.
14651492
In 'atomic' mode (default), dict keys represent the atomic number associated with each
@@ -1565,6 +1592,7 @@ def __init__(
15651592
qchem_version=qchem_version,
15661593
max_scf_cycles=self.max_scf_cycles,
15671594
plot_cubes=plot_cubes,
1595+
output_wavefunction=output_wavefunction,
15681596
nbo_params=nbo_params,
15691597
vdw_mode=vdw_mode,
15701598
cdft_constraints=cdft_constraints,
@@ -1597,6 +1625,7 @@ def __init__(
15971625
custom_smd: str | None = None,
15981626
max_scf_cycles: int = 100,
15991627
plot_cubes: bool = False,
1628+
output_wavefunction: bool = False,
16001629
nbo_params: dict | None = None,
16011630
opt_variables: dict[str, list] | None = None,
16021631
scan_variables: dict[str, list] | None = None,
@@ -1670,6 +1699,8 @@ def __init__(
16701699
Refer to the QChem manual for further details.
16711700
max_scf_cycles (int): Maximum number of SCF iterations. (Default: 100)
16721701
plot_cubes (bool): Whether to write CUBE files of the electron density. (Default: False)
1702+
output_wavefunction (bool): Whether to write a wavefunction (*.wfn) file of the electron density
1703+
(Default: False)
16731704
overwrite_inputs (dict): Dictionary of QChem input sections to add or overwrite variables.
16741705
The currently available sections (keys) are rem, pcm,
16751706
solvent, smx, opt, scan, van_der_waals, and plots. The value of each key is a
@@ -1714,6 +1745,7 @@ def __init__(
17141745
qchem_version=qchem_version,
17151746
max_scf_cycles=self.max_scf_cycles,
17161747
plot_cubes=plot_cubes,
1748+
output_wavefunction=output_wavefunction,
17171749
nbo_params=nbo_params,
17181750
overwrite_inputs=overwrite_inputs,
17191751
vdw_mode=vdw_mode,

src/pymatgen/io/vasp/inputs.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2867,9 +2867,9 @@ def from_directory(
28672867
full_zpath = zpath(os.path.join(input_dir, fname))
28682868
sub_dct[fname.lower()] = ftype.from_file(full_zpath) # type: ignore[attr-defined]
28692869
except FileNotFoundError: # handle the case where there is no KPOINTS file
2870-
sub_dct[fname.lower()] = None
2870+
sub_dct[fname.lower()] = None # type: ignore[assignment]
28712871

2872-
sub_dct["optional_files"] = {
2872+
sub_dct["optional_files"] = { # type: ignore[assignment]
28732873
fname: ftype.from_file(os.path.join(input_dir, fname)) for fname, ftype in (optional_files or {}).items()
28742874
}
28752875

0 commit comments

Comments
 (0)