Skip to content

Commit

Permalink
Minor Q-Chem updates (materialsproject#292)
Browse files Browse the repository at this point in the history
* gdm_neg_precon_error

* model initial hessian for delocalized coords

* fix bug

* fix bug

* tiny initial hessian tweak

* also save 131.0

* save orbital coeff file

* debugging

* Fix fileman freq bug and add test

* also save 132.0 scratch file

* pre-commit auto-fixes

* Address comments

* compress new_test_files/gdm_neg_precon_error.(qin|qout)

---------

Co-authored-by: Janosh Riebesell <[email protected]>
  • Loading branch information
samblau and janosh authored Sep 21, 2023
1 parent 85cf4aa commit 4d78d09
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 8 deletions.
27 changes: 20 additions & 7 deletions custodian/qchem/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def correct(self):
# Try forcing a new initial guess at each iteration
elif (
self.qcinp.rem.get("scf_guess_always", "none").lower() != "true"
and len(self.outdata.get("energy_trajectory", [])) > 0
and "molecule_from_last_geometry" in self.outdata
):
self.qcinp.rem["scf_guess_always"] = "true"
actions.append({"scf_guess_always": "true"})
Expand All @@ -130,7 +130,7 @@ def correct(self):
"maxiter"
] = self.geom_max_cycles
actions.append({"geom_max_cycles:": self.geom_max_cycles})
if len(self.outdata.get("energy_trajectory")) > 1:
if "molecule_from_last_geometry" in self.outdata:
self.qcinp.molecule = self.outdata.get("molecule_from_last_geometry")
actions.append({"molecule": "molecule_from_last_geometry"})

Expand Down Expand Up @@ -164,7 +164,7 @@ def correct(self):
if self.qcinp.rem.get("thresh", "10") != "14":
self.qcinp.rem["thresh"] = "14"
actions.append({"thresh": "14"})
elif len(self.outdata.get("energy_trajectory")) > 1:
elif "molecule_from_last_geometry" in self.outdata:
self.qcinp.molecule = self.outdata.get("molecule_from_last_geometry")
actions.append({"molecule": "molecule_from_last_geometry"})
if self.qcinp.rem.get("scf_algorithm", "diis").lower() == "diis":
Expand All @@ -183,7 +183,7 @@ def correct(self):
if self.qcinp.rem.get("thresh", "10") != "14":
self.qcinp.rem["thresh"] = "14"
actions.append({"thresh": "14"})
elif len(self.outdata.get("energy_trajectory")) > 1:
elif "molecule_from_last_geometry" in self.outdata:
self.qcinp.molecule = self.outdata.get("molecule_from_last_geometry")
actions.append({"molecule": "molecule_from_last_geometry"})

Expand All @@ -198,9 +198,15 @@ def correct(self):
"coordinates"
] = "delocalized"
actions.append({"coordinates": "delocalized"})
if self.qcinp.geom_opt.get("initial_hessian", "none") != "read":
self.qcinp.geom_opt["initial_hessian"] = "model"
actions.append({"initial_hessian": "model"})
elif self.qcinp.geom_opt["coordinates"] == "delocalized":
self.qcinp.geom_opt["coordinates"] = "cartesian" # pylint: disable=unsupported-assignment-operation
actions.append({"coordinates": "cartesian"})
if self.qcinp.geom_opt.get("initial_hessian", "none") == "model":
del self.qcinp.geom_opt["initial_hessian"]
actions.append({"initial_hessian": "deleted"})

elif "premature_end_FileMan_error" in self.errors:
# Given defaults, the first two handlers will typically be skipped.
Expand All @@ -210,13 +216,13 @@ def correct(self):
if self.qcinp.rem.get("thresh", "10") != "14":
self.qcinp.rem["thresh"] = "14"
actions.append({"thresh": "14"})
elif self.qcinp.rem.get("job_type") == "opt" or "optimization":
elif self.qcinp.rem.get("job_type") == "opt" or self.qcinp.rem.get("job_type") == "optimization":
if self.qcinp.rem.get("scf_guess_always", "none").lower() != "true":
self.qcinp.rem["scf_guess_always"] = "true"
actions.append({"scf_guess_always": "true"})
else:
print("Don't know how to fix a FileMan error for an opt while always generating a new SCF guess!")
elif self.qcinp.rem.get("job_type") == "freq" or "frequency":
elif self.qcinp.rem.get("job_type") == "freq" or self.qcinp.rem.get("job_type") == "frequency":
self.qcinp.rem["cpscf_nseg"] = str(self.outdata["cpscf_nseg"] + 1)
actions.append({"cpscf_nseg": str(self.outdata["cpscf_nseg"] + 1)})

Expand Down Expand Up @@ -321,6 +327,13 @@ def correct(self):
self.qcinp.rem["cpscf_nseg"] = str(self.outdata["cpscf_nseg"] + 1)
actions.append({"cpscf_nseg": str(self.outdata["cpscf_nseg"] + 1)})

elif "gdm_neg_precon_error" in self.errors:
if "molecule_from_last_geometry" in self.outdata:
self.qcinp.molecule = self.outdata.get("molecule_from_last_geometry")
actions.append({"molecule": "molecule_from_last_geometry"})
else:
print("Not sure how to fix gdm_neg_precon_error on the first SCF!")

elif "mem_static_too_small" in self.errors:
# mem_static should never exceed 2000 MB according to the Q-Chem manual
self.qcinp.rem["mem_static"] = "2000"
Expand Down Expand Up @@ -374,7 +387,7 @@ def correct(self):
and "initial_hessian" in self.qcinp.geom_opt
) and str(self.qcinp.geom_opt["initial_hessian"]).lower() == "read":
del self.qcinp.geom_opt["initial_hessian"]
actions.append({"geom_opt.initial_hessian-read": "deleted"})
actions.append({"initial_hessian": "deleted"})
os.rename(self.input_file, self.input_file + ".last")
self.qcinp.write_file(self.input_file)
return {"errors": self.errors, "warnings": self.warnings, "actions": actions}
5 changes: 4 additions & 1 deletion custodian/qchem/jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ def setup(self):
def postprocess(self):
"""Renames and removes scratch files after running QChem."""
scratch_dir = os.path.join(os.environ["QCSCRATCH"], "scratch")
for file in ["HESS", "GRAD", "plots/dens.0.cube"]:
for file in ["HESS", "GRAD", "plots/dens.0.cube", "131.0", "53.0", "132.0"]:
file_path = os.path.join(scratch_dir, file)
if os.path.exists(file_path):
shutil.copy(file_path, os.getcwd())
Expand Down Expand Up @@ -161,6 +161,9 @@ def run(self):
if os.path.exists(os.path.join(os.environ["QCSCRATCH"], "132.0")):
os.mkdir(local_scratch)
shutil.move(os.path.join(os.environ["QCSCRATCH"], "132.0"), local_scratch)
if os.path.exists(os.path.join(os.environ["QCSCRATCH"], "53.0")):
os.mkdir(local_scratch, exist_ok=True)
shutil.move(os.path.join(os.environ["QCSCRATCH"], "53.0"), local_scratch)
with open(self.qclog_file, "w") as qclog:
return subprocess.Popen(self.current_command, stdout=qclog, shell=True) # pylint: disable=R1732

Expand Down
30 changes: 30 additions & 0 deletions custodian/qchem/tests/test_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,36 @@ def test_OOS_read_hess(self):
]
self._check_equivalent_inputs(os.path.join(test_dir, "OOS_read_hess_next.qin"), "mol.qin")

def test_gdm_neg_precon_error(self):
shutil.copyfile(
os.path.join(test_dir, "gdm_neg_precon_error.qin.gz"),
os.path.join(scr_dir, "mol.qin.gz"),
)
shutil.copyfile(
os.path.join(test_dir, "gdm_neg_precon_error.qout.gz"),
os.path.join(scr_dir, "mol.qout.gz"),
)
h = QChemErrorHandler(input_file="mol.qin", output_file="mol.qout")
h.check()
d = h.correct()
assert d["errors"] == ["gdm_neg_precon_error"]
assert d["actions"] == [{"molecule": "molecule_from_last_geometry"}]

def test_fileman_cpscf_nseg_error(self):
shutil.copyfile(
os.path.join(test_dir, "fileman_cpscf.qin.gz"),
os.path.join(scr_dir, "mol.qin.gz"),
)
shutil.copyfile(
os.path.join(test_dir, "fileman_cpscf.qout.gz"),
os.path.join(scr_dir, "mol.qout.gz"),
)
h = QChemErrorHandler(input_file="mol.qin", output_file="mol.qout")
h.check()
d = h.correct()
assert d["errors"] == ["premature_end_FileMan_error"]
assert d["actions"] == [{"cpscf_nseg": "3"}]

def tearDown(self):
os.chdir(cwd)
shutil.rmtree(scr_dir)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

0 comments on commit 4d78d09

Please sign in to comment.