def test_OptFF(self): myjob = QCJob.opt_with_frequency_flattener( qchem_command="qchem -slurm", max_cores=32, input_file="mol.qin", output_file="mol.qout") expected_next = QCJob(qchem_command="qchem -slurm", max_cores=32, multimode="openmp", input_file="mol.qin", output_file="mol.qout", suffix=".opt_0", backup=True).as_dict() self.assertEqual(next(myjob).as_dict(), expected_next) expected_next = QCJob(qchem_command="qchem -slurm", max_cores=32, multimode="openmp", input_file="mol.qin", output_file="mol.qout", suffix=".freq_0", backup=False).as_dict() self.assertEqual(next(myjob).as_dict(), expected_next) self.assertEqual( QCInput.from_file( os.path.join( test_dir, "disconnected_but_converged/mol.qin.freq_0")).as_dict(), QCInput.from_file(os.path.join(scr_dir, "mol.qin")).as_dict()) self.assertRaises(StopIteration, myjob.__next__)
def test_OptFF(self): myjob = QCJob.opt_with_frequency_flattener( qchem_command="qchem -slurm", max_cores=32, input_file="mol.qin", output_file="mol.qout", linked=True, transition_state=True, freq_before_opt=True, ) expected_next = QCJob( qchem_command="qchem -slurm", max_cores=32, multimode="openmp", input_file="mol.qin", output_file="mol.qout", suffix=".freq_pre", save_scratch=True, backup=True, ).as_dict() self.assertEqual(next(myjob).as_dict(), expected_next) expected_next = QCJob( qchem_command="qchem -slurm", max_cores=32, multimode="openmp", input_file="mol.qin", output_file="mol.qout", suffix=".ts_0", save_scratch=True, backup=False, ).as_dict() self.assertEqual(next(myjob).as_dict(), expected_next) self.assertEqual( QCInput.from_file(os.path.join(test_dir, "fftsopt_freqfirst/mol.qin.ts_0")).as_dict(), QCInput.from_file(os.path.join(scr_dir, "mol.qin")).as_dict(), ) shutil.copyfile( os.path.join(scr_dir, "mol.qin"), os.path.join(scr_dir, "mol.qin.ts_0"), ) expected_next = QCJob( qchem_command="qchem -slurm", max_cores=32, multimode="openmp", input_file="mol.qin", output_file="mol.qout", suffix=".freq_0", save_scratch=True, backup=False, ).as_dict() self.assertEqual(next(myjob).as_dict(), expected_next) self.assertEqual( QCInput.from_file(os.path.join(test_dir, "fftsopt_freqfirst/mol.qin.freq_0")).as_dict(), QCInput.from_file(os.path.join(scr_dir, "mol.qin")).as_dict(), ) shutil.copyfile( os.path.join(scr_dir, "mol.qin"), os.path.join(scr_dir, "mol.qin.freq_0"), ) self.assertRaises(StopIteration, myjob.__next__)
def _verify_inputs(self): user_qin = QCInput.from_file(os.path.join(os.getcwd(), "mol.qin")) # Check mol.qin ref_qin = QCInput.from_file(os.path.join(self["ref_dir"], "mol.qin")) np.testing.assert_equal(ref_qin.molecule.species, user_qin.molecule.species) np.testing.assert_allclose( ref_qin.molecule.cart_coords, user_qin.molecule.cart_coords, atol=0.0001) for key in ref_qin.rem: if user_qin.rem.get(key) != ref_qin.rem.get(key): raise ValueError("Rem key {} is inconsistent!".format(key)) if ref_qin.opt is not None: for key in ref_qin.opt: if user_qin.opt.get(key) != ref_qin.opt.get(key): raise ValueError("Opt key {} is inconsistent!".format(key)) if ref_qin.pcm is not None: for key in ref_qin.pcm: if user_qin.pcm.get(key) != ref_qin.pcm.get(key): raise ValueError("PCM key {} is inconsistent!".format(key)) if ref_qin.solvent is not None: for key in ref_qin.solvent: if user_qin.solvent.get(key) != ref_qin.solvent.get(key): raise ValueError( "Solvent key {} is inconsistent!".format(key)) logger.info("RunQChemFake: verified input successfully")
def test_smd_write(self): test_molecule = QCInput.from_file( os.path.join(test_dir, "new_qchem_files/pcm.qin")).molecule dict_set = QChemDictSet( molecule=test_molecule, job_type="opt", basis_set="6-31g*", scf_algorithm="diis", dft_rung=5, smd_solvent="water", max_scf_cycles=35, ) dict_set.write("mol.qin") test_dict = QCInput.from_file("mol.qin").as_dict() rem = { "job_type": "opt", "basis": "6-31G*", "max_scf_cycles": "35", "method": "wb97mv", "geom_opt_max_cycles": "200", "gen_scfman": "true", "scf_algorithm": "diis", "xc_grid": "3", "solvent_method": "smd", "ideriv": "1", "symmetry": "false", "sym_ignore": "true", "resp_charges": "true", } qc_input = QCInput(molecule=test_molecule, rem=rem, smx={"solvent": "water"}) for k, v in qc_input.as_dict().items(): self.assertEqual(v, test_dict[k]) os.remove("mol.qin")
def _verify_inputs(self): input_file = self.get("input_file", "mol.qin") user_qin = QCInput.from_file(os.path.join(os.getcwd(), "mol.qin")) # Check mol.qin ref_qin = QCInput.from_file(os.path.join(self["ref_dir"], input_file)) np.testing.assert_equal(ref_qin.molecule.species, user_qin.molecule.species) np.testing.assert_allclose(ref_qin.molecule.cart_coords, user_qin.molecule.cart_coords, atol=0.0001) for key in ref_qin.rem: if user_qin.rem.get(key) != ref_qin.rem.get(key): raise ValueError("Rem key {} is inconsistent!".format(key)) if ref_qin.opt is not None: for key in ref_qin.opt: if user_qin.opt.get(key) != ref_qin.opt.get(key): raise ValueError("Opt key {} is inconsistent!".format(key)) if ref_qin.pcm is not None: for key in ref_qin.pcm: if user_qin.pcm.get(key) != ref_qin.pcm.get(key): raise ValueError("PCM key {} is inconsistent!".format(key)) if ref_qin.solvent is not None: for key in ref_qin.solvent: if user_qin.solvent.get(key) != ref_qin.solvent.get(key): raise ValueError( "Solvent key {} is inconsistent!".format(key)) logger.info("RunQChemFake: verified input successfully")
def _check_equivalent_inputs(self, input1, input2): self.assertEqual( QCInput.from_file(input1).molecule, QCInput.from_file(input2).molecule) self.assertEqual( QCInput.from_file(input1).rem, QCInput.from_file(input2).rem)
def test_write_file_from_OptSet(self): from pymatgen.io.qchem.sets import OptSet odd_dict = loadfn(os.path.join(os.path.dirname(__file__), "odd.json")) odd_mol = odd_dict["spec"]["_tasks"][0]["molecule"] qcinp = OptSet(odd_mol) qcinp.write_file(os.path.join(os.path.dirname(__file__), "test.qin")) test_dict = QCInput.from_file(os.path.join(os.path.dirname(__file__), "test.qin")).as_dict() test_ref_dict = QCInput.from_file(os.path.join(os.path.dirname(__file__), "test_ref.qin")).as_dict() for key in test_dict: self.assertEqual(test_dict[key], test_ref_dict[key]) os.remove(os.path.join(os.path.dirname(__file__), "test.qin"))
def setUpClass(cls): co_species = ["C", "O"] co_coords = [[0.0, 0.0, 0.0], [1.3, 0.0, 0.0]] cls.co_mol = Molecule(co_species, co_coords) cls.co_opt_ref_in = QCInput.from_file( os.path.join(files_dir, "qchem", "co_qc.in")) cls.opt_mol_ref_in = QCInput.from_file( os.path.join(files_dir, "qchem", "to_opt.qin")) cls.opt_mol = cls.opt_mol_ref_in.molecule cls.opt_mol_pcm_ref_in = QCInput.from_file( os.path.join(files_dir, "qchem", "to_opt_pcm.qin"))
def test_write_file_from_OptSet(self): from pymatgen.io.qchem.sets import OptSet odd_dict = loadfn(os.path.join(os.path.dirname(__file__), "odd.json")) odd_mol = odd_dict["spec"]["_tasks"][0]["molecule"] qcinp = OptSet(odd_mol) qcinp.write_file(os.path.join(os.path.dirname(__file__), "test.qin")) test_dict = QCInput.from_file(os.path.join(os.path.dirname(__file__), "test.qin")).as_dict() test_ref_dict = QCInput.from_file(os.path.join(os.path.dirname(__file__), "test_ref.qin")).as_dict() for key in test_dict: self.assertEqual(test_dict[key], test_ref_dict[key]) os.remove(os.path.join(os.path.dirname(__file__), "test.qin"))
def test_pcm_init(self): test_molecule = QCInput.from_file( os.path.join(test_dir, "new_qchem_files/pcm.qin")).molecule test_FreqSet = FreqSet(molecule=test_molecule, pcm_dielectric=10.0) self.assertEqual( test_FreqSet.rem, { 'job_type': 'freq', 'gen_scfman': 'true', 'basis': 'def2-tzvppd', 'max_scf_cycles': 200, 'method': 'wb97xd', 'scf_algorithm': 'diis', 'xc_grid': '3', 'solvent_method': 'pcm', 'symmetry': 'false', 'sym_ignore': 'true', 'resp_charges': 'true' }) self.assertEqual( test_FreqSet.pcm, { 'heavypoints': '194', 'hpoints': '194', 'radii': 'uff', 'theory': 'cpcm', 'vdwscale': '1.1' }) self.assertEqual(test_FreqSet.solvent, {'dielectric': 10.0}) self.assertEqual(test_FreqSet.molecule, test_molecule)
def test_init(self): test_molecule = QCInput.from_file( os.path.join(test_dir, "new_qchem_files/pcm.qin")).molecule test_DictSet = QChemDictSet( molecule=test_molecule, job_type='opt', basis_set='6-31G*', scf_algorithm='diis') self.assertEqual( test_DictSet.rem, { 'job_type': 'opt', 'gen_scfman': 'true', 'basis': '6-31g*', 'max_scf_cycles': 200, 'method': 'wb97xv', 'scf_algorithm': 'diis', 'xc_grid': '3', 'geom_opt_max_cycles': 200, 'symmetry': 'false', 'sym_ignore': 'true', 'resp_charges': 'true' }) self.assertEqual(test_DictSet.pcm, {}) self.assertEqual(test_DictSet.solvent, {}) self.assertEqual(test_DictSet.smx, {}) self.assertEqual(test_DictSet.molecule, test_molecule)
def test_overwrite_input(self): test_molecule = QCInput.from_file( os.path.join(test_dir, "new_qchem_files/pcm.qin")).molecule overwrite_inputs = { "rem": { 'method': 'b3lyp', 'basis': '6-31g*', 'thresh': 10, "xc_grid": "000150000302" } } test_OptSet = OptSet( molecule=test_molecule, overwrite_inputs=overwrite_inputs) act_rem = { 'job_type': 'opt', 'gen_scfman': 'true', 'basis': '6-31g*', 'max_scf_cycles': 200, 'method': 'b3lyp', 'scf_algorithm': 'diis', 'xc_grid': '000150000302', 'geom_opt_max_cycles': 200, 'thresh': 10, 'symmetry': 'false', 'sym_ignore': 'true', 'resp_charges': 'true' } self.assertDictEqual(act_rem, test_OptSet.rem)
def __init__( self, input_file="mol.qin", output_file="mol.qout", rca_gdm_thresh=1.0e-3, scf_max_cycles=200, ): """ Initializes the error handler from a set of input and output files. Args: input_file (str): Name of the QChem input file. output_file (str): Name of the QChem output file. rca_gdm_thresh (float): The threshold for the prior scf algorithm. If last deltaE is larger than the threshold try RCA_DIIS first, else, try DIIS_GDM first. scf_max_cycles (int): The max iterations to set to fix SCF failure. """ self.input_file = input_file self.output_file = output_file self.scf_max_cycles = scf_max_cycles self.geom_max_cycles = geom_max_cycles self.qcinp = QCInput.from_file(self.input_file) self.outdata = None self.errors = None self.qchem_job = qchem_job
def test_double_FF_opt(self): # location of test files test_double_FF_files = os.path.join(module_dir, "..", "..", "test_files", "double_FF_wf") # define starting molecule and workflow object initial_qcin = QCInput.from_file( os.path.join(test_double_FF_files, "block", "launcher_first", "mol.qin.opt_0")) initial_mol = initial_qcin.molecule real_wf = get_wf_double_FF_opt( molecule=initial_mol, pcm_dielectric=10.0, qchem_input_params={ "basis_set": "6-311++g**", "scf_algorithm": "diis", "overwrite_inputs": { "rem": { "sym_ignore": "true" } } }) # use powerup to replace run with fake run ref_dirs = { "first_FF_no_pcm": os.path.join(test_double_FF_files, "block", "launcher_first"), "second_FF_with_pcm": os.path.join(test_double_FF_files, "block", "launcher_second") } fake_wf = use_fake_qchem(real_wf, ref_dirs) self.lp.add_wf(fake_wf) rapidfire( self.lp, fworker=FWorker(env={"max_cores": 32, "db_file": os.path.join(db_dir, "db.json")})) wf_test = self.lp.get_wf_by_fw_id(1) self.assertTrue( all([s == "COMPLETED" for s in wf_test.fw_states.values()])) first_FF = self.get_task_collection().find_one({ "task_label": "first_FF_no_pcm" }) self.assertEqual(first_FF["calcs_reversed"][0]["input"]["solvent"], None) self.assertEqual(first_FF["num_frequencies_flattened"], 1) first_FF_final_mol = Molecule.from_dict( first_FF["output"]["optimized_molecule"]) second_FF = self.get_task_collection().find_one({ "task_label": "second_FF_with_pcm" }) self.assertEqual(second_FF["calcs_reversed"][0]["input"]["solvent"], {"dielectric": "10.0"}) self.assertEqual(second_FF["num_frequencies_flattened"], 1) second_FF_initial_mol = Molecule.from_dict( second_FF["input"]["initial_molecule"]) self.assertEqual(first_FF_final_mol, second_FF_initial_mol)
def test_overwrite_input(self): test_molecule = QCInput.from_file( os.path.join(test_dir, "new_qchem_files/pcm.qin")).molecule overwrite_inputs = { "rem": { "method": "b3lyp", "basis": "6-31g*", "thresh": 10, "xc_grid": "000150000302", } } test_OptSet = OptSet(molecule=test_molecule, overwrite_inputs=overwrite_inputs) act_rem = { "job_type": "opt", "gen_scfman": "true", "basis": "6-31g*", "max_scf_cycles": 200, "method": "b3lyp", "scf_algorithm": "diis", "xc_grid": "000150000302", "geom_opt_max_cycles": 200, "thresh": 10, "symmetry": "false", "sym_ignore": "true", "resp_charges": "true", } self.assertDictEqual(act_rem, test_OptSet.rem)
def test_parse_pass_write(self): input_file = "test.qin.opt_1" output_file = "test.qout.opt_1" calc_dir = os.path.join(module_dir, "..", "..", "test_files", "FF_working") p_task = QChemToDb( calc_dir=calc_dir, input_file=input_file, output_file=output_file, db_file=">>db_file<<") fw1 = Firework([p_task]) w_task = WriteInputFromIOSet( qchem_input_set="OptSet", write_to_dir=module_dir) fw2 = Firework([w_task], parents=fw1) wf = Workflow([fw1, fw2]) self.lp.add_wf(wf) rapidfire( self.lp, fworker=FWorker(env={"db_file": os.path.join(db_dir, "db.json")})) test_mol = QCInput.from_file(os.path.join(module_dir, "mol.qin")).molecule np.testing.assert_equal(self.act_mol.species, test_mol.species) np.testing.assert_equal(self.act_mol.cart_coords, test_mol.cart_coords)
def test_write_input_from_io_set_diff_mol(self): ft = WriteInputFromIOSet(molecule=self.opt_mol, qchem_input_set="OptSet") ft.run_task({}) test_dict = QCInput.from_file("mol.qin").as_dict() for k, v in self.opt_mol_ref_in.as_dict().items(): self.assertEqual(v, test_dict[k])
def test_full_init(self): test_molecule = QCInput.from_file( os.path.join(test_dir, "new_qchem_files/pcm.qin")).molecule test_DictSet = QChemDictSet( molecule=test_molecule, job_type='opt', basis_set='6-31g*', scf_algorithm='diis', dft_rung=1, pcm_dielectric=10.0, max_scf_cycles=35) self.assertEqual( test_DictSet.rem, { 'job_type': 'opt', 'gen_scfman': 'true', 'basis': '6-31g*', 'max_scf_cycles': 35, 'exchange': 'b3lyp', 'geom_opt_max_cycles': 200, 'scf_algorithm': 'diis', 'solvent_method': 'pcm' }) self.assertEqual( test_DictSet.pcm, { 'heavypoints': '194', 'hpoints': '194', 'radii': 'uff', 'theory': 'cpcm', 'vdwscale': '1.1' }) self.assertEqual(test_DictSet.solvent, {'dielectric': 10.0}) self.assertEqual(test_DictSet.molecule, test_molecule)
def test_pcm_init(self): test_molecule = QCInput.from_file( os.path.join(test_dir, "new_qchem_files/pcm.qin")).molecule test_SPSet = SinglePointSet( molecule=test_molecule, pcm_dielectric=10.0) self.assertEqual( test_SPSet.rem, { 'job_type': 'sp', 'gen_scfman': 'true', 'basis': '6-311++g*', 'max_scf_cycles': 200, 'method': 'wb97xd', 'scf_algorithm': 'gdm', 'solvent_method': 'pcm' }) self.assertEqual( test_SPSet.pcm, { 'heavypoints': '194', 'hpoints': '194', 'radii': 'uff', 'theory': 'cpcm', 'vdwscale': '1.1' }) self.assertEqual(test_SPSet.solvent, {'dielectric': 10.0}) self.assertEqual(test_SPSet.molecule, test_molecule)
def test_pcm_init(self): test_molecule = QCInput.from_file( os.path.join(test_dir, "new_qchem_files/pcm.qin")).molecule test_FreqSet = FreqSet(molecule=test_molecule, pcm_dielectric=10.0) self.assertEqual( test_FreqSet.rem, { "job_type": "freq", "gen_scfman": "true", "basis": "def2-tzvppd", "max_scf_cycles": 200, "method": "wb97xd", "scf_algorithm": "diis", "xc_grid": "3", "solvent_method": "pcm", "symmetry": "false", "sym_ignore": "true", "resp_charges": "true", }, ) self.assertEqual( test_FreqSet.pcm, { "heavypoints": "194", "hpoints": "194", "radii": "uff", "theory": "cpcm", "vdwscale": "1.1", }, ) self.assertEqual(test_FreqSet.solvent, {"dielectric": 10.0}) self.assertEqual(test_FreqSet.molecule, test_molecule)
def test_init(self): test_molecule = QCInput.from_file( os.path.join(test_dir, "new_qchem_files/pcm.qin")).molecule test_DictSet = QChemDictSet( molecule=test_molecule, job_type="opt", basis_set="6-31G*", scf_algorithm="diis", ) self.assertEqual( test_DictSet.rem, { "job_type": "opt", "gen_scfman": "true", "basis": "6-31g*", "max_scf_cycles": 200, "method": "wb97xv", "scf_algorithm": "diis", "xc_grid": "3", "geom_opt_max_cycles": 200, "symmetry": "false", "sym_ignore": "true", "resp_charges": "true", }, ) self.assertEqual(test_DictSet.pcm, {}) self.assertEqual(test_DictSet.solvent, {}) self.assertEqual(test_DictSet.smx, {}) self.assertEqual(test_DictSet.molecule, test_molecule)
def test_parse_pass_rotate_write(self): input_file = "pt_gs_wb97mv_tz_initial.in" output_file = "pt_gs_wb97mv_tz_initial_1_job.out" calc_dir = os.path.join(module_dir, "..", "..", "test_files") p_task = QChemToDb( calc_dir=calc_dir, input_file=input_file, output_file=output_file, db_file=">>db_file<<") fw1 = Firework([p_task]) atom_indexes = [6, 8, 9, 10] angle = 90.0 rot_task = RotateTorsion(atom_indexes=atom_indexes, angle=angle) w_task = WriteInputFromIOSet( qchem_input_set="OptSet", write_to_dir=module_dir) fw2 = Firework([rot_task, w_task], parents=fw1) wf = Workflow([fw1, fw2]) self.lp.add_wf(wf) rapidfire( self.lp, fworker=FWorker(env={"db_file": os.path.join(db_dir, "db.json")})) test_mol = QCInput.from_file(os.path.join(module_dir, "mol.qin")).molecule act_mol = Molecule.from_file( os.path.join(module_dir, "..", "..", "test_files", "pt_rotated_90.0.xyz")) np.testing.assert_equal(act_mol.species, test_mol.species) np.testing.assert_allclose( act_mol.cart_coords, test_mol.cart_coords, atol=0.0001)
def test_pcm_init(self): test_molecule = QCInput.from_file( os.path.join(test_dir, "new_qchem_files/pcm.qin")).molecule test_SPSet = SinglePointSet(molecule=test_molecule, pcm_dielectric=10.0) self.assertEqual( test_SPSet.rem, { 'job_type': 'sp', 'gen_scfman': 'true', 'basis': '6-311++g*', 'max_scf_cycles': 200, 'method': 'wb97xd', 'scf_algorithm': 'gdm', 'solvent_method': 'pcm' }) self.assertEqual( test_SPSet.pcm, { 'heavypoints': '194', 'hpoints': '194', 'radii': 'uff', 'theory': 'cpcm', 'vdwscale': '1.1' }) self.assertEqual(test_SPSet.solvent, {'dielectric': 10.0}) self.assertEqual(test_SPSet.molecule, test_molecule)
def test_full_init(self): test_molecule = QCInput.from_file( os.path.join(test_dir, "new_qchem_files/pcm.qin")).molecule test_DictSet = QChemDictSet(molecule=test_molecule, job_type='opt', basis_set='6-31g*', scf_algorithm='diis', dft_rung=1, pcm_dielectric=10.0, max_scf_cycles=35) self.assertEqual( test_DictSet.rem, { 'job_type': 'opt', 'gen_scfman': 'true', 'basis': '6-31g*', 'max_scf_cycles': 35, 'exchange': 'b3lyp', 'geom_opt_max_cycles': 200, 'scf_algorithm': 'diis', 'solvent_method': 'pcm' }) self.assertEqual( test_DictSet.pcm, { 'heavypoints': '194', 'hpoints': '194', 'radii': 'uff', 'theory': 'cpcm', 'vdwscale': '1.1' }) self.assertEqual(test_DictSet.solvent, {'dielectric': 10.0}) self.assertEqual(test_DictSet.molecule, test_molecule)
def test_write_input_from_io_set_write_dir(self): ft = WriteInputFromIOSet(molecule=self.co_mol, qchem_input_set="OptSet", write_to_dir=module_dir) ft.run_task({}) test_dict = QCInput.from_file(os.path.join(module_dir, "mol.qin")).as_dict() for k, v in self.co_opt_ref_in.as_dict().items(): self.assertEqual(v, test_dict[k])
def test_pcm_write(self): test_molecule = QCInput.from_file( os.path.join(test_dir, "new_qchem_files/pcm.qin")).molecule dict_set = QChemDictSet( molecule=test_molecule, job_type="opt", basis_set="6-31g*", scf_algorithm="diis", dft_rung=5, pcm_dielectric=10.0, max_scf_cycles=35, ) dict_set.write("mol.qin") test_dict = QCInput.from_file("mol.qin").as_dict() rem = { "job_type": "opt", "basis": "6-31G*", "max_scf_cycles": "35", "method": "wb97mv", "geom_opt_max_cycles": "200", "gen_scfman": "true", "scf_algorithm": "diis", "xc_grid": "3", "solvent_method": "pcm", "symmetry": "false", "sym_ignore": "true", "resp_charges": "true", } pcm = { "heavypoints": "194", "hpoints": "194", "radii": "uff", "theory": "cpcm", "vdwscale": "1.1", } qc_input = QCInput(molecule=test_molecule, rem=rem, pcm=pcm, solvent={"dielectric": "10.0"}) for k, v in qc_input.as_dict().items(): self.assertEqual(v, test_dict[k]) os.remove("mol.qin")
def test_OptFF(self): myjob = QCJob.opt_with_frequency_flattener(qchem_command="qchem", max_cores=32, input_file="test.qin", output_file="test.qout") expected_next = QCJob( qchem_command="qchem", max_cores=32, multimode="openmp", input_file="test.qin", output_file="test.qout", suffix=".opt_0", backup=True).as_dict() self.assertEqual(next(myjob).as_dict(),expected_next) expected_next = QCJob( qchem_command="qchem", max_cores=32, multimode="openmp", input_file="test.qin", output_file="test.qout", suffix=".freq_0", backup=False).as_dict() self.assertEqual(next(myjob).as_dict(),expected_next) self.assertEqual(QCInput.from_file(os.path.join(test_dir,"FF_working/test.qin.freq_0")).as_dict(),QCInput.from_file(os.path.join(scr_dir,"test.qin")).as_dict()) expected_next = QCJob( qchem_command="qchem", max_cores=32, multimode="openmp", input_file="test.qin", output_file="test.qout", suffix=".opt_1", backup=False).as_dict() self.assertEqual(next(myjob).as_dict(),expected_next) self.assertEqual(QCInput.from_file(os.path.join(test_dir,"FF_working/test.qin.opt_1")).as_dict(),QCInput.from_file(os.path.join(scr_dir,"test.qin")).as_dict()) expected_next = QCJob( qchem_command="qchem", max_cores=32, multimode="openmp", input_file="test.qin", output_file="test.qout", suffix=".freq_1", backup=False).as_dict() self.assertEqual(next(myjob).as_dict(),expected_next) self.assertEqual(QCInput.from_file(os.path.join(test_dir,"FF_working/test.qin.freq_1")).as_dict(),QCInput.from_file(os.path.join(scr_dir,"test.qin")).as_dict()) self.assertRaises(StopIteration,myjob.__next__)
def test_OptFF(self): self.maxDiff = None myjob = QCJob.opt_with_frequency_flattener(qchem_command="qchem", max_cores=32, input_file="test.qin", output_file="test.qout", sp_params=self.sp_params) expected_next = QCJob(qchem_command="qchem", max_cores=32, multimode="openmp", input_file="test.qin", output_file="test.qout", suffix=".opt_0", backup=True).as_dict() self.assertEqual(next(myjob).as_dict(), expected_next) expected_next = QCJob(qchem_command="qchem", max_cores=32, multimode="openmp", input_file="test.qin", output_file="test.qout", suffix=".freq_0", backup=False).as_dict() self.assertEqual(next(myjob).as_dict(), expected_next) self.assertEqual( QCInput.from_file(join( test_dir, "standard/rct_1_471171.in.freq_0")).as_dict(), QCInput.from_file(join(scr_dir, "test.qin")).as_dict()) expected_next = QCJob(qchem_command="qchem", max_cores=32, multimode="openmp", input_file="test.qin", output_file="test.qout", suffix=".sp", backup=True).as_dict() self.assertEqual(next(myjob).as_dict(), expected_next) self.assertEqual( QCInput.from_file(join(test_dir, "standard/rct_1_471171.in.sp")).as_dict(), QCInput.from_file(join(scr_dir, "test.qin")).as_dict()) self.assertRaises(StopIteration, myjob.__next__)
def test_read_write_nbo7(self): qcinp = QCInput.from_file(os.path.join(PymatgenTest.TEST_FILES_DIR, "molecules", "new_qchem_files", "nbo7.qin")) qcinp.write_file(os.path.join(os.path.dirname(__file__), "test_nbo7.qin")) test_file = open(os.path.join(PymatgenTest.TEST_FILES_DIR, "molecules", "new_qchem_files", "nbo7.qin")) ref_file = open(os.path.join(os.path.dirname(__file__), "test_nbo7.qin")) for l_test, l_ref in zip(test_file, ref_file): # By default, if this statement fails the offending line will be printed assert l_test == l_ref test_file.close() ref_file.close() os.remove(os.path.join(os.path.dirname(__file__), "test_nbo7.qin"))
def test_custom_smd_write(self): test_molecule = QCInput.from_file( os.path.join(test_dir, "new_qchem_files/pcm.qin")).molecule dict_set = QChemDictSet( molecule=test_molecule, job_type='opt', basis_set='6-31g*', scf_algorithm='diis', dft_rung=5, smd_solvent="custom", custom_smd="90.00,1.415,0.00,0.735,20.2,0.00,0.00", max_scf_cycles=35) dict_set.write("mol.qin") test_dict = QCInput.from_file("mol.qin").as_dict() rem = { "job_type": "opt", "basis": "6-31G*", "max_scf_cycles": '35', "method": "wb97mv", "geom_opt_max_cycles": '200', "gen_scfman": 'true', "scf_algorithm": "diis", "xc_grid": '3', "solvent_method": "smd", "ideriv": "1", 'symmetry': 'false', 'sym_ignore': 'true', 'resp_charges': 'true' } qc_input = QCInput(molecule=test_molecule, rem=rem, smx={"solvent": "other"}) for k, v in qc_input.as_dict().items(): self.assertEqual(v, test_dict[k]) os.remove("mol.qin") with open("solvent_data") as sd: lines = sd.readlines() self.assertEqual(lines[0], "90.00,1.415,0.00,0.735,20.2,0.00,0.00") os.remove("solvent_data")
def test_OptFF(self): myjob = QCJob.opt_with_frequency_flattener(qchem_command="qchem", input_file="test.qin", output_file="test.qout") expected_next = QCJob( qchem_command="qchem", multimode="openmp", input_file="test.qin", output_file="test.qout", suffix=".opt_0", backup=True).as_dict() self.assertEqual(next(myjob).as_dict(),expected_next) expected_next = QCJob( qchem_command="qchem", multimode="openmp", input_file="test.qin", output_file="test.qout", suffix=".freq_0", backup=False).as_dict() self.assertEqual(next(myjob).as_dict(),expected_next) self.assertEqual(QCInput.from_file(os.path.join(test_dir,"FF_working/test.qin.freq_0")).as_dict(),QCInput.from_file(os.path.join(scr_dir,"test.qin")).as_dict()) expected_next = QCJob( qchem_command="qchem", multimode="openmp", input_file="test.qin", output_file="test.qout", suffix=".opt_1", backup=False).as_dict() self.assertEqual(next(myjob).as_dict(),expected_next) self.assertEqual(QCInput.from_file(os.path.join(test_dir,"FF_working/test.qin.opt_1")).as_dict(),QCInput.from_file(os.path.join(scr_dir,"test.qin")).as_dict()) expected_next = QCJob( qchem_command="qchem", multimode="openmp", input_file="test.qin", output_file="test.qout", suffix=".freq_1", backup=False).as_dict() self.assertEqual(next(myjob).as_dict(),expected_next) self.assertEqual(QCInput.from_file(os.path.join(test_dir,"FF_working/test.qin.freq_1")).as_dict(),QCInput.from_file(os.path.join(scr_dir,"test.qin")).as_dict()) self.assertRaises(StopIteration,myjob.__next__)
def test_write_custom_input(self): mol = self.co_mol rem = { "job_type": "opt", "basis": "6-311++G*", "max_scf_cycles": 200, "method": "wB97xd", "geom_opt_max_cycles": 200, "gen_scfman": True, "scf_algorithm": "gdm" } ft = WriteCustomInput(molecule=mol, rem=rem) ft.run_task({}) test_dict = QCInput.from_file("mol.qin").as_dict() for k, v in self.co_opt_ref_in.as_dict().items(): self.assertEqual(v, test_dict[k])
def test_smd_init(self): test_molecule = QCInput.from_file( os.path.join(test_dir, "new_qchem_files/pcm.qin")).molecule test_SPSet = SinglePointSet(molecule=test_molecule, smd_solvent='water') self.assertEqual( test_SPSet.rem, { 'job_type': 'sp', 'gen_scfman': 'true', 'basis': '6-311++g*', 'max_scf_cycles': 200, 'method': 'wb97xd', 'scf_algorithm': 'gdm', 'solvent_method': 'smd' }) self.assertEqual(test_SPSet.smx, {'solvent': 'water'}) self.assertEqual(test_SPSet.molecule, test_molecule)
def test_init(self): test_molecule = QCInput.from_file( os.path.join(test_dir, "new_qchem_files/pcm.qin")).molecule test_FreqSet = FreqSet(molecule=test_molecule) self.assertEqual( test_FreqSet.rem, { 'job_type': 'freq', 'gen_scfman': 'true', 'basis': '6-311++g*', 'max_scf_cycles': 200, 'method': 'wb97xd', 'scf_algorithm': 'gdm' }) self.assertEqual(test_FreqSet.pcm, {}) self.assertEqual(test_FreqSet.solvent, {}) self.assertEqual(test_FreqSet.molecule, test_molecule)
def process_qchemrun(dir_name, taskname, input_file, output_file): """ Process a QChem calculation, aka an input/output pair. """ qchem_input_file = os.path.join(dir_name, input_file) qchem_output_file = os.path.join(dir_name, output_file) d = QCOutput(qchem_output_file).data temp_input = QCInput.from_file(qchem_input_file) d["input"] = {} d["input"]["molecule"] = temp_input.molecule d["input"]["rem"] = temp_input.rem d["input"]["opt"] = temp_input.opt d["input"]["pcm"] = temp_input.pcm d["input"]["solvent"] = temp_input.solvent d["task"] = {"type": taskname, "name": taskname} return d
def test_init(self): test_molecule = QCInput.from_file( os.path.join(test_dir, "new_qchem_files/pcm.qin")).molecule test_FreqSet = FreqSet(molecule=test_molecule) self.assertEqual( test_FreqSet.rem, { 'job_type': 'freq', 'gen_scfman': 'true', 'basis': '6-311++g*', 'max_scf_cycles': 200, 'method': 'wb97xd', 'scf_algorithm': 'gdm' }) self.assertEqual(test_FreqSet.pcm, {}) self.assertEqual(test_FreqSet.solvent, {}) self.assertEqual(test_FreqSet.molecule, test_molecule)
def test_overwrite_input_addition(self): test_molecule = QCInput.from_file( os.path.join(test_dir, "new_qchem_files/pcm.qin")).molecule overwrite_inputs = {"rem": {'thresh': 14}} test_OptSet = OptSet(molecule=test_molecule, overwrite_inputs=overwrite_inputs) act_rem = { 'job_type': 'opt', 'gen_scfman': 'true', 'basis': '6-311++g*', 'max_scf_cycles': 200, 'method': 'wb97xd', 'scf_algorithm': 'gdm', 'geom_opt_max_cycles': 200, 'thresh': 14 } self.assertDictEqual(act_rem, test_OptSet.rem)
def test_overwrite_input_addition(self): test_molecule = QCInput.from_file( os.path.join(test_dir, "new_qchem_files/pcm.qin")).molecule overwrite_inputs = {"rem": {'thresh': 14}} test_OptSet = OptSet( molecule=test_molecule, overwrite_inputs=overwrite_inputs) act_rem = { 'job_type': 'opt', 'gen_scfman': 'true', 'basis': '6-311++g*', 'max_scf_cycles': 200, 'method': 'wb97xd', 'scf_algorithm': 'gdm', 'geom_opt_max_cycles': 200, 'thresh': 14 } self.assertDictEqual(act_rem, test_OptSet.rem)
def test_double_solvation(self): test_molecule = QCInput.from_file( os.path.join(test_dir, "new_qchem_files/pcm.qin")).molecule raised_error = False dict_set = None try: dict_set = QChemDictSet(molecule=test_molecule, job_type='opt', basis_set='6-31g*', scf_algorithm='diis', dft_rung=1, pcm_dielectric=10.0, smd_solvent="water", max_scf_cycles=35) except ValueError: raised_error = True self.assertTrue(raised_error) self.assertEqual(dict_set, None)
def test_init(self): test_molecule = QCInput.from_file( os.path.join(test_dir, "new_qchem_files/pcm.qin")).molecule test_DictSet = QChemDictSet( molecule=test_molecule, job_type='opt', basis_set='6-31G*', scf_algorithm='diis') self.assertEqual( test_DictSet.rem, { 'job_type': 'opt', 'gen_scfman': 'true', 'basis': '6-31g*', 'max_scf_cycles': 200, 'method': 'wb97xd', 'scf_algorithm': 'diis', 'geom_opt_max_cycles': 200 }) self.assertEqual(test_DictSet.pcm, {}) self.assertEqual(test_DictSet.solvent, {}) self.assertEqual(test_DictSet.molecule, test_molecule)
def __init__(self, input_file="mol.qin", output_file="mol.qout", rca_gdm_thresh=1.0E-3, scf_max_cycles=200): """ Initializes the error handler from a set of input and output files. Args: input_file (str): Name of the QChem input file. output_file (str): Name of the QChem output file. rca_gdm_thresh (float): The threshold for the prior scf algorithm. If last deltaE is larger than the threshold try RCA_DIIS first, else, try DIIS_GDM first. scf_max_cycles (int): The max iterations to set to fix SCF failure. """ self.input_file = input_file self.output_file = output_file self.scf_max_cycles = scf_max_cycles self.geom_max_cycles = geom_max_cycles self.qcinp = QCInput.from_file(self.input_file) self.outdata = None self.errors = None self.qchem_job = qchem_job
def test_Fragmentation(self): with patch("atomate.qchem.firetasks.fragmenter.FWAction") as FWAction_patch: mock_FWAction = MagicMock() FWAction_patch.return_value = mock_FWAction mock_FWAction.as_dict.return_value = {'stored_data': {}, 'exit': False, 'update_spec': {}, 'mod_spec': [], 'additions': [], 'detours': [], 'defuse_children': False, 'defuse_workflow': False} # location of test files test_FF_then_fragment_files = os.path.join(module_dir, "..", "..", "test_files", "FF_then_fragment_wf") # define starting molecule and workflow object initial_qcin = QCInput.from_file( os.path.join(test_FF_then_fragment_files, "block", "launcher_first", "mol.qin.opt_0")) initial_mol = initial_qcin.molecule real_wf = get_fragmentation_wf(molecule=initial_mol, depth=0, do_triplets=False) # use powerup to replace run with fake run ref_dirs = { "first FF": os.path.join(test_FF_then_fragment_files, "block", "launcher_first"), "fragment and FF_opt": os.path.join(test_FF_then_fragment_files, "block", "launcher_second") } fake_wf = use_fake_qchem(real_wf, ref_dirs) self.lp.add_wf(fake_wf) rapidfire( self.lp, fworker=FWorker(env={"max_cores": 32, "db_file": os.path.join(db_dir, "db.json")}), pdb_on_exception=True) first_FF = self.get_task_collection().find_one({ "task_label": "first FF" }) self.assertEqual(first_FF["calcs_reversed"][0]["input"]["solvent"], None) self.assertEqual(first_FF["num_frequencies_flattened"], 0) self.assertEqual(len(FWAction_patch.call_args[1]["additions"]), 5 * 3)
def correct(self): backup({self.input_file, self.output_file}) actions = [] self.qcinp = QCInput.from_file(self.input_file) if "SCF_failed_to_converge" in self.errors: # Check number of SCF cycles. If not set or less than scf_max_cycles, # increase to that value and rerun. If already set, check if # scf_algorithm is unset or set to DIIS, in which case set to GDM. # Otherwise, tell user to call SCF error handler and do nothing. if str(self.qcinp.rem.get("max_scf_cycles")) != str( self.scf_max_cycles): self.qcinp.rem["max_scf_cycles"] = self.scf_max_cycles actions.append({"max_scf_cycles": self.scf_max_cycles}) elif self.qcinp.rem.get("scf_algorithm", "diis").lower() == "diis": self.qcinp.rem["scf_algorithm"] = "gdm" actions.append({"scf_algorithm": "gdm"}) elif self.qcinp.rem.get("scf_algorithm", "gdm").lower() == "gdm": self.qcinp.rem["scf_algorithm"] = "diis_gdm" actions.append({"scf_algorithm": "diis_gdm"}) else: print( "More advanced changes may impact the SCF result. Use the SCF error handler" ) elif "out_of_opt_cycles" in self.errors: # Check number of opt cycles. If less than geom_max_cycles, increase # to that value, set last geom as new starting geom and rerun. if str(self.qcinp.rem.get( "geom_opt_max_cycles")) != str(self.geom_max_cycles): self.qcinp.rem["geom_opt_max_cycles"] = self.geom_max_cycles actions.append({"geom_max_cycles:": self.scf_max_cycles}) if len(self.outdata.get("energy_trajectory")) > 1: self.qcinp.molecule = self.outdata.get( "molecule_from_last_geometry") actions.append({"molecule": "molecule_from_last_geometry"}) # If already at geom_max_cycles, often can just get convergence by restarting # from the geometry of the last cycle. But we'll also save any structural # changes that happened along the way. else: self.opt_error_history += [self.outdata["structure_change"]] if len(self.opt_error_history) > 1: if self.opt_error_history[-1] == "no_change": # If no structural changes occured in two consecutive optimizations, # and we still haven't converged, then just exit. return {"errors": self.errors, "actions": None, "opt_error_history": self.opt_error_history} self.qcinp.molecule = self.outdata.get("molecule_from_last_geometry") actions.append({"molecule": "molecule_from_last_geometry"}) elif "unable_to_determine_lamda" in self.errors: # Set last geom as new starting geom and rerun. If no opt cycles, # use diff SCF strat? Diff initial guess? Change basis? if len(self.outdata.get("energy_trajectory")) > 1: self.qcinp.molecule = self.outdata.get( "molecule_from_last_geometry") actions.append({"molecule": "molecule_from_last_geometry"}) elif self.qcinp.rem.get("scf_algorithm", "diis").lower() == "diis": self.qcinp.rem["scf_algorithm"] = "rca_diis" actions.append({"scf_algorithm": "rca_diis"}) if self.qcinp.rem.get("gen_scfman"): self.qcinp.rem["gen_scfman"] = False actions.append({"gen_scfman": False}) else: print( "Use a different initial guess? Perhaps a different basis?" ) elif "linear_dependent_basis" in self.errors: # DIIS -> RCA_DIIS. If already RCA_DIIS, change basis? if self.qcinp.rem.get("scf_algorithm", "diis").lower() == "diis": self.qcinp.rem["scf_algorithm"] = "rca_diis" actions.append({"scf_algorithm": "rca_diis"}) if self.qcinp.rem.get("gen_scfman"): self.qcinp.rem["gen_scfman"] = False actions.append({"gen_scfman": False}) else: print("Perhaps use a better basis?") elif "failed_to_transform_coords" in self.errors: # Check for symmetry flag in rem. If not False, set to False and rerun. # If already False, increase threshold? if not self.qcinp.rem.get("sym_ignore") or self.qcinp.rem.get( "symmetry"): self.qcinp.rem["sym_ignore"] = True self.qcinp.rem["symmetry"] = False actions.append({"sym_ignore": True}) actions.append({"symmetry": False}) else: print("Perhaps increase the threshold?") elif "input_file_error" in self.errors: print( "Something is wrong with the input file. Examine error message by hand." ) return {"errors": self.errors, "actions": None} elif "failed_to_read_input" in self.errors: # Almost certainly just a temporary problem that will not be encountered again. Rerun job as-is. actions.append({"rerun job as-is"}) elif "IO_error" in self.errors: # Almost certainly just a temporary problem that will not be encountered again. Rerun job as-is. actions.append({"rerun job as-is"}) elif "read_molecule_error" in self.errors: # Almost certainly just a temporary problem that will not be encountered again. Rerun job as-is. actions.append({"rerun job as-is"}) elif "never_called_qchem" in self.errors: # Almost certainly just a temporary problem that will not be encountered again. Rerun job as-is. actions.append({"rerun job as-is"}) elif "unknown_error" in self.errors: print("Examine error message by hand.") return {"errors": self.errors, "actions": None} else: # You should never get here. If correct is being called then errors should have at least one entry, # in which case it should have been caught by the if/elifs above. print( "If you get this message, something has gone terribly wrong!") return {"errors": self.errors, "actions": None} os.rename(self.input_file, self.input_file + ".last") self.qcinp.write_file(self.input_file) return {"errors": self.errors, "actions": actions}
def test_torsion_potential(self): # location of test files test_tor_files = os.path.join(module_dir, "..", "..", "test_files", "torsion_wf") # define starting molecule and torsion potential workflow object initial_qcin = QCInput.from_file( os.path.join(test_tor_files, "initial_opt", "mol.qin")) initial_mol = initial_qcin.molecule atom_indexes = [6, 8, 9, 10] angles = [0.0, 90.0, 180.0] rem = [] # add the first rem section rem.append({ "jobtype": "opt", "method": "wb97m-v", "basis": "def2-tzvppd", "gen_scfman": "true", "geom_opt_max_cycles": 75, "max_scf_cycles": 300, "scf_algorithm": "diis", "scf_guess": "sad", "sym_ignore": "true", "symmetry": "false", "thresh": 14 }) # the second rem section rem.append({ "jobtype": "opt", "method": "wb97m-v", "basis": "def2-tzvppd", "geom_opt_max_cycles": 75, "max_scf_cycles": 300, "scf_algorithm": "diis", "scf_guess": "sad", "sym_ignore": "true", "symmetry": "false", "thresh": 14 }) real_wf = get_wf_torsion_potential( molecule=initial_mol, atom_indexes=atom_indexes, angles=angles, rem=rem, db_file=">>db_file<<") # use powerup to replace run with fake run # def ref_dirs ref_dirs = { "initial_opt": os.path.join(test_tor_files, "initial_opt"), "opt_0": os.path.join(test_tor_files, "opt_0"), "opt_90": os.path.join(test_tor_files, "opt_90"), "opt_180": os.path.join(test_tor_files, "opt_180") } fake_wf = use_fake_qchem(real_wf, ref_dirs) self.lp.add_wf(fake_wf) rapidfire( self.lp, fworker=FWorker(env={"db_file": os.path.join(db_dir, "db.json")})) wf_test = self.lp.get_wf_by_fw_id(1) self.assertTrue( all([s == "COMPLETED" for s in wf_test.fw_states.values()])) # Checking of the inputs happens in fake_run_qchem so there is no point to retest the inputs # Check the output info that gets inserted in the DB init_opt = self.get_task_collection().find_one({ "task_label": "initial_opt" }) init_opt_final_mol = Molecule.from_dict( init_opt["output"]["optimized_molecule"]) init_opt_final_e = init_opt["output"]["final_energy"] # parse output file act_init_opt_out = QCOutput( os.path.join(test_tor_files, "initial_opt", "mol.qout")) act_init_opt_mol = act_init_opt_out.data[ "molecule_from_optimized_geometry"] act_init_opt_final_e = act_init_opt_out.data["final_energy"] np.testing.assert_equal(act_init_opt_mol.species, init_opt_final_mol.species) np.testing.assert_allclose( act_init_opt_mol.cart_coords, init_opt_final_mol.cart_coords, atol=0.0001) np.testing.assert_equal(act_init_opt_final_e, init_opt_final_e) # Optimization of 0 torsion opt_0 = self.get_task_collection().find_one({"task_label": "opt_0"}) opt_0_final_mol = Molecule.from_dict( opt_0["output"]["optimized_molecule"]) opt_0_final_e = opt_0["output"]["final_energy"] # parse output file act_opt_0_out = QCOutput( os.path.join(test_tor_files, "opt_0", "mol.qout")) act_opt_0_mol = act_opt_0_out.data["molecule_from_optimized_geometry"] act_opt_0_final_e = act_opt_0_out.data["final_energy"] np.testing.assert_equal(act_opt_0_mol.species, opt_0_final_mol.species) np.testing.assert_allclose( act_opt_0_mol.cart_coords, opt_0_final_mol.cart_coords, atol=0.0001) np.testing.assert_equal(act_opt_0_final_e, opt_0_final_e) # Optimization of 90 torsion opt_90 = self.get_task_collection().find_one({"task_label": "opt_90"}) opt_90_final_mol = Molecule.from_dict( opt_90["output"]["optimized_molecule"]) opt_90_final_e = opt_90["output"]["final_energy"] # parse output file act_opt_90_out = QCOutput( os.path.join(test_tor_files, "opt_90", "mol.qout")) act_opt_90_mol = act_opt_90_out.data[ "molecule_from_optimized_geometry"] act_opt_90_final_e = act_opt_90_out.data["final_energy"] np.testing.assert_equal(act_opt_90_mol.species, opt_90_final_mol.species) np.testing.assert_allclose( act_opt_90_mol.cart_coords, opt_90_final_mol.cart_coords, atol=0.0001) np.testing.assert_equal(act_opt_90_final_e, opt_90_final_e) # Optimization of 180 torsion opt_180 = self.get_task_collection().find_one({ "task_label": "opt_180" }) opt_180_final_mol = Molecule.from_dict( opt_180["output"]["optimized_molecule"]) opt_180_final_e = opt_180["output"]["final_energy"] # parse output file act_opt_180_out = QCOutput( os.path.join(test_tor_files, "opt_180", "mol.qout")) act_opt_180_mol = act_opt_180_out.data[ "molecule_from_optimized_geometry"] act_opt_180_final_e = act_opt_180_out.data["final_energy"] np.testing.assert_equal(act_opt_180_mol.species, opt_180_final_mol.species) np.testing.assert_allclose( act_opt_180_mol.cart_coords, opt_180_final_mol.cart_coords, atol=0.0001) np.testing.assert_equal(act_opt_180_final_e, opt_180_final_e)
def opt_with_frequency_flattener(cls, qchem_command, multimode="openmp", input_file="mol.qin", output_file="mol.qout", qclog_file="mol.qclog", max_iterations=10, max_molecule_perturb_scale=0.3, check_connectivity=True, **QCJob_kwargs): """ Optimize a structure and calculate vibrational frequencies to check if the structure is in a true minima. If a frequency is negative, iteratively perturbe the geometry, optimize, and recalculate frequencies until all are positive, aka a true minima has been found. Args: qchem_command (str): Command to run QChem. multimode (str): Parallelization scheme, either openmp or mpi. input_file (str): Name of the QChem input file. output_file (str): Name of the QChem output file. max_iterations (int): Number of perturbation -> optimization -> frequency iterations to perform. Defaults to 10. max_molecule_perturb_scale (float): The maximum scaled perturbation that can be applied to the molecule. Defaults to 0.3. check_connectivity (bool): Whether to check differences in connectivity introduced by structural perturbation. Defaults to True. **QCJob_kwargs: Passthrough kwargs to QCJob. See :class:`custodian.qchem.jobs.QCJob`. """ min_molecule_perturb_scale = 0.1 scale_grid = 10 perturb_scale_grid = ( max_molecule_perturb_scale - min_molecule_perturb_scale ) / scale_grid if not os.path.exists(input_file): raise AssertionError('Input file must be present!') orig_opt_input = QCInput.from_file(input_file) orig_opt_rem = copy.deepcopy(orig_opt_input.rem) orig_freq_rem = copy.deepcopy(orig_opt_input.rem) orig_freq_rem["job_type"] = "freq" first = True reversed_direction = False num_neg_freqs = [] for ii in range(max_iterations): yield (QCJob( qchem_command=qchem_command, multimode=multimode, input_file=input_file, output_file=output_file, qclog_file=qclog_file, suffix=".opt_" + str(ii), backup=first, **QCJob_kwargs)) first = False opt_outdata = QCOutput(output_file + ".opt_" + str(ii)).data if opt_outdata["structure_change"] == "unconnected_fragments" and not opt_outdata["completion"]: print("Unstable molecule broke into unconnected fragments which failed to optimize! Exiting...") break else: freq_QCInput = QCInput( molecule=opt_outdata.get("molecule_from_optimized_geometry"), rem=orig_freq_rem, opt=orig_opt_input.opt, pcm=orig_opt_input.pcm, solvent=orig_opt_input.solvent) freq_QCInput.write_file(input_file) yield (QCJob( qchem_command=qchem_command, multimode=multimode, input_file=input_file, output_file=output_file, qclog_file=qclog_file, suffix=".freq_" + str(ii), backup=first, **QCJob_kwargs)) outdata = QCOutput(output_file + ".freq_" + str(ii)).data errors = outdata.get("errors") if len(errors) != 0: raise AssertionError('No errors should be encountered while flattening frequencies!') if outdata.get('frequencies')[0] > 0.0: print("All frequencies positive!") break else: num_neg_freqs += [sum(1 for freq in outdata.get('frequencies') if freq < 0)] if len(num_neg_freqs) > 1: if num_neg_freqs[-1] == num_neg_freqs[-2] and not reversed_direction: reversed_direction = True elif num_neg_freqs[-1] == num_neg_freqs[-2] and reversed_direction: if len(num_neg_freqs) < 3: raise AssertionError("ERROR: This should only be possible after at least three frequency flattening iterations! Exiting...") else: raise Exception("ERROR: Reversing the perturbation direction still could not flatten any frequencies. Exiting...") elif num_neg_freqs[-1] != num_neg_freqs[-2] and reversed_direction: reversed_direction = False negative_freq_vecs = outdata.get("frequency_mode_vectors")[0] structure_successfully_perturbed = False for molecule_perturb_scale in np.arange( max_molecule_perturb_scale, min_molecule_perturb_scale, -perturb_scale_grid): new_coords = perturb_coordinates( old_coords=outdata.get("initial_geometry"), negative_freq_vecs=negative_freq_vecs, molecule_perturb_scale=molecule_perturb_scale, reversed_direction=reversed_direction) new_molecule = Molecule( species=outdata.get('species'), coords=new_coords, charge=outdata.get('charge'), spin_multiplicity=outdata.get('multiplicity')) if check_connectivity: old_molgraph = MoleculeGraph.with_local_env_strategy(outdata.get("initial_molecule"), OpenBabelNN(), reorder=False, extend_structure=False) new_molgraph = MoleculeGraph.with_local_env_strategy(new_molecule, OpenBabelNN(), reorder=False, extend_structure=False) if old_molgraph.isomorphic_to(new_molgraph): structure_successfully_perturbed = True break if not structure_successfully_perturbed: raise Exception( "ERROR: Unable to perturb coordinates to remove negative frequency without changing the connectivity! Exiting..." ) new_opt_QCInput = QCInput( molecule=new_molecule, rem=orig_opt_rem, opt=orig_opt_input.opt, pcm=orig_opt_input.pcm, solvent=orig_opt_input.solvent) new_opt_QCInput.write_file(input_file)