def freq_fw(self, charge, spin_multiplicity, fw_id_cal, fw_id_db, priority=None, method=None): if not method: if self.large: method = "PBE-D3/6-31+G*" else: method = "B3lYP/6-31+G*" task_type = "vibrational frequency" state_name = self.get_state_name(charge, spin_multiplicity) title = self.molname + " " + state_name + " " + method + " " + task_type exchange, correlation, basis_set, aux_basis, rem_params, method_token, ecp = self. \ get_exchange_correlation_basis_auxbasis_remparams(method, self.mol) if exchange.lower() in ["xygjos"]: rem_params["IDERIV"] = 1 qctask = QcTask(self.mol, charge=charge, spin_multiplicity=spin_multiplicity, jobtype="freq", title=title, exchange=exchange, correlation=correlation, basis_set=basis_set, aux_basis_set=aux_basis, ecp=ecp, rem_params=rem_params) if self.large: qctask.set_scf_algorithm_and_iterations(iterations=100) qcinp = QcInput([qctask]) spec = self.base_spec() spec["qcinp"] = qcinp.as_dict() spec['task_type'] = task_type spec['charge'] = charge spec['spin_multiplicity'] = spin_multiplicity spec['run_tags']['methods'] = method_token spec["qm_method"] = method if priority: spec['_priority'] = priority task_name = self.molname + ' ' + state_name + ' ' + task_type from rubicon.firetasks.qchem.multistep_qchem_task \ import QChemFrequencyDBInsertionTask fw_freq_cal = Firework([QChemTask()], spec=spec, name=task_name, fw_id=fw_id_cal) spec_db = copy.deepcopy(spec) del spec_db['_dupefinder'] spec_db['_allow_fizzled_parents'] = True spec_db['task_type'] = task_type + ' DB Insertion' del spec_db["_trackers"][:2] task_name_db = task_name + " DB Insertion" fw_freq_db = Firework([QChemFrequencyDBInsertionTask()], spec=spec_db, name=task_name_db, fw_id=fw_id_db) return fw_freq_cal, fw_freq_db
def main(): parser = argparse.ArgumentParser( description="Assign mixed basis set by list of ranges") parser.add_argument("-i", "--input", dest="input", type=str, required=True, help="the QChem input filename") parser.add_argument( "-b", "--basis", dest="basis", type=str, required=True, help= "The file contain the list of basis sets by four columns: 1) start atom index (1 based);" "2) end atom index; 3) basis set; 4) comments") parser.add_argument( "-o", "--output", dest="output", type=str, required=True, help="the QChem input filename with the mixed basis set") options = parser.parse_args() qcinp_no_basis = QcInput.from_file(options.input) mol_with_basis = assign_basis_set_by_range(qcinp=qcinp_no_basis, basis_def_file=options.basis) mol_with_basis.write_file(options.output)
def from_dict(cls, d): h = QChemErrorHandler(input_file=d["input_file"], output_file=d["output_file"], ex_backup_list=d["ex_backup_list"], rca_gdm_thresh=d["rca_gdm_thresh"], scf_max_cycles=d["scf_max_cycles"], geom_max_cycles=d["geom_max_cycles"]) h.outdata = d["outdata"] h.qcinp = QcInput.from_dict(d["qcinp"]) if d["qcinp"] else None h.error_step_id = d["error_step_id"] h.errors = d["errors"] h.fix_step = QcTask.from_dict(d["fix_step"]) if d["fix_step"] else None return h
def main(): parser = argparse.ArgumentParser( description= "Replace the atom coordinates of the first job in QChem input file with the coordinates from" "an XYZ file") parser.add_argument("-i", "--input", dest="input", type=str, required=True, help="the QChem input filename") parser.add_argument("-c", "--coords", dest="coords", type=str, required=True, help="The XYZ file contains the new coords") parser.add_argument("-v", "--velocity", dest="velocity", type=str, default=None, help="The AIMD velocity file") parser.add_argument( "-o", "--output", dest="output", type=str, required=True, help="the QChem input filename with the coordinates from the XYZ file") options = parser.parse_args() qcinp = QcInput.from_file(options.input) charge, spin = qcinp.jobs[0].charge, qcinp.jobs[0].spin_multiplicity if options.velocity is None: new_mol = Molecule.from_file(options.coords) else: mxyz = XYZ.from_file(options.coords) new_mol = mxyz.all_molecules[-1] qcinp.jobs[0].params["rem"].pop("aimd_init_veloc", None) qcnv = QcNucVeloc(options.velocity) assert len(mxyz.molecules) == len(qcnv.velocities) qcinp.jobs[0].set_velocities(qcnv.velocities[-1]) if charge is not None: new_mol.set_charge_and_spin(charge, spin) qcinp.jobs[0].mol = new_mol qcinp.write_file(options.output) print( "created new QChem input file {new_file} using {old_inp} as an template and filled with coordinates " \ "from {coord_file}".format(old_inp=options.input, coord_file=options.coords, new_file=options.output))
def _get_qcinp_from_fw_spec(fw_spec): if isinstance(fw_spec["qcinp"], dict): qcinp = QcInput.from_dict(fw_spec["qcinp"]) else: qcinp = fw_spec["qcinp"] if 'mol' in fw_spec: if isinstance(fw_spec["mol"], dict): mol = Molecule.from_dict(fw_spec["mol"]) else: mol = fw_spec["mol"] for qj in qcinp.jobs: if isinstance(qj.mol, Molecule): qj.mol = copy.deepcopy(mol) return qcinp
def check(self): # Checks output file for errors. self.outdata = QcOutput(self.output_file).data self.qcinp = QcInput.from_file(self.input_file) self.error_step_id = None self.errors = None self.fix_step = None for i, od in enumerate(self.outdata): if od["has_error"]: self.error_step_id = i self.fix_step = self.qcinp.jobs[i] self.errors = sorted(list(set(od["errors"]))) return True return False
def call_qchem_task(filename, solvent=None, mixed_basis=None, mixed_aux_basis=None): base_filename = os.path.splitext(filename)[0] output_filename = base_filename + ".qcout" qcinp = QcInput.from_file(filename) solvent_token = set_solvent_data(qcinp, solvent) QChemTask.run_qchem(qcinp, solvent_token, mixed_aux_basis, mixed_basis, input_file=filename, output_file=output_filename, gzipped=False)
def spawn_opt_freq_wf(mol, molname, mission, additional_user_tags, priority, update_spec, charge, spin_multiplicity, grid, qm_method): fw_creator = QChemFireWorkCreator( mol=mol, molname=molname, mission=mission, additional_user_tags=additional_user_tags, priority=priority, update_spec=update_spec) geom_fwid_cal, geom_fwid_db = -1, -2 freq_fwid_cal, freq_fwid_db = -3, -4 geom_fw_cal, geom_fw_db = fw_creator.geom_fw(charge, spin_multiplicity, geom_fwid_cal, geom_fwid_db, method=qm_method) geom_fw_cal.spec["run_tags"]["task_type_amend"] = "imaginary " \ "frequency elimination" freq_fw_cal, freq_fw_db = fw_creator.freq_fw(charge, spin_multiplicity, freq_fwid_cal, freq_fwid_db, method=qm_method) freq_fw_cal.spec["run_tags"]["task_type_amend"] = "imaginary " \ "frequency elimination" if grid: for fw in [geom_fw_cal, geom_fw_db, freq_fw_cal, freq_fw_db]: if isinstance(fw.spec["qcinp"], dict): qcinp = QcInput.from_dict(fw.spec["qcinp"]) else: qcinp = fw.spec["qcinp"] for j in qcinp.jobs: j.set_dft_grid(*grid) j.set_integral_threshold(12) if j.params["rem"]["jobtype"] == "opt": j.scale_geom_opt_threshold(0.1, 0.1, 0.1) j.set_geom_max_iterations(100) fw.spec["qcinp"] = qcinp.as_dict() fw.spec["run_tags"]["grid"] = grid wf = Workflow( [geom_fw_cal, geom_fw_db, freq_fw_cal, freq_fw_db], links_dict={ geom_fwid_db: freq_fwid_cal, geom_fwid_cal: geom_fwid_db, freq_fwid_cal: freq_fwid_db }) return wf
def _set_qchem_memory(self, qcinp=None): instance_ratio = 1.0 if "QCSCRATCH" in os.environ and \ ("/tmp" in os.environ["QCSCRATCH"] or "/dev/shm" in os.environ["QCSCRATCH"]): instance_ratio = 0.5 nprocs = 1 if "-np" in self.current_command: nprocs = int(self.current_command[self.current_command.index("-np") + 1]) mem_per_proc = self.total_physical_memory * 1000 // nprocs if self.large_static_mem: static_ratio = 0.4 else: static_ratio = 0.1 total_mem = int(mem_per_proc * instance_ratio) static_mem = int(total_mem * static_ratio) if not qcinp: qcinp = QcInput.from_file(self.input_file) for j in qcinp.jobs: j.set_memory(total=total_mem, static=static_mem) qcinp.write_file(self.input_file)
def main(): parser = argparse.ArgumentParser( description= "Replace the atom coordinates of the first job in QChem input file with the coordinates from" "an XYZ file") parser.add_argument("-i", "--input", dest="input", type=str, required=True, help="the QChem input filename") parser.add_argument("-c", "--coords", dest="coords", type=str, required=True, help="The XYZ file contains the new coords") parser.add_argument( "-o", "--output", dest="output", type=str, required=True, help="the QChem input filename with the coordinates from the XYZ file") options = parser.parse_args() qcinp = QcInput.from_file(options.input) charge, spin = qcinp.jobs[0].charge, qcinp.jobs[0].spin_multiplicity new_mol = Molecule.from_file(options.coords) if charge is not None: new_mol.set_charge_and_spin(charge, spin) qcinp.jobs[0].mol = new_mol qcinp.write_file(options.output) print( "created new QChem input file {new_file} using {old_inp} as an template and filled with coordinates " \ "from {coord_file}".format(old_inp=options.input, coord_file=options.coords, new_file=options.output))
def _run_qchem_on_alcf(self, log_file_object=None): parent_qcinp = QcInput.from_file(self.input_file) njobs = len(parent_qcinp.jobs) return_codes = [] alcf_cmds = [] qc_jobids = [] for i, j in enumerate(parent_qcinp.jobs): qsub_cmd = copy.deepcopy(self.current_command) sub_input_filename = "alcf_{}_{}".format(i + 1, self.input_file) sub_output_filename = "alcf_{}_{}".format(i + 1, self.output_file) sub_log_filename = "alcf_{}_{}".format(i + 1, self.qclog_file) qsub_cmd[-2] = sub_input_filename sub_qcinp = QcInput([copy.deepcopy(j)]) if "scf_guess" in sub_qcinp.jobs[0].params["rem"] and \ sub_qcinp.jobs[0].params["rem"]["scf_guess"] == "read": sub_qcinp.jobs[0].params["rem"].pop("scf_guess") if i > 0: if isinstance(j.mol, str) and j.mol == "read": prev_qcout_filename = "alcf_{}_{}".format( i + 1 - 1, self.output_file) prev_qcout = QcOutput(prev_qcout_filename) prev_final_mol = prev_qcout.data[0]["molecules"][-1] j.mol = prev_final_mol sub_qcinp.write_file(sub_input_filename) logging.info("The command to run QChem is {}".format( ' '.join(qsub_cmd))) alcf_cmds.append(qsub_cmd) p = subprocess.Popen(qsub_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = p.communicate() qc_jobid = int(out.strip()) qc_jobids.append(qc_jobid) cqwait_cmd = shlex.split("cqwait {}".format(qc_jobid)) subprocess.call(cqwait_cmd) output_file_name = "{}.output".format(qc_jobid) cobaltlog_file_name = "{}.cobaltlog".format(qc_jobid) with open(cobaltlog_file_name) as f: cobaltlog_last_line = f.readlines()[-1] exit_code_pattern = re.compile( "an exit code of (?P<code>\d+);") m = exit_code_pattern.search(cobaltlog_last_line) if m: rc = float(m.group("code")) else: rc = -99999 return_codes.append(rc) for name_change_trial in range(10): if not os.path.exists(output_file_name): message = "{} is not found in {}, {}th wait " \ "for 5 mins\n".format( output_file_name, os.getcwd(), name_change_trial) logging.info(message) if log_file_object: log_file_object.writelines([message]) time.sleep(60 * 5) pass else: message = "Found qchem output file {} in {}, change file " \ "name\n".format(output_file_name, os.getcwd(), name_change_trial) logging.info(message) if log_file_object: log_file_object.writelines([message]) break log_file_object.flush() os.fsync(log_file_object.fileno()) shutil.move(output_file_name, sub_output_filename) shutil.move(cobaltlog_file_name, sub_log_filename) overall_return_code = min(return_codes) with open(self.output_file, "w") as out_file_object: for i, job_cmd, rc, qc_jobid in zip(range(njobs), alcf_cmds, return_codes, qc_jobids): sub_output_filename = "alcf_{}_{}".format( i + 1, self.output_file) sub_log_filename = "alcf_{}_{}".format(i + 1, self.qclog_file) with open(sub_output_filename) as sub_out_file_object: header_lines = [ "Running Job {} of {} {}\n".format( i + 1, njobs, self.input_file), " ".join(job_cmd) + "\n" ] if i > 0: header_lines = ['', ''] + header_lines sub_out = sub_out_file_object.readlines() out_file_object.writelines(header_lines) out_file_object.writelines(sub_out) if rc < 0 and rc != -99999: out_file_object.writelines([ "Application {} exit codes: {}\n".format( qc_jobid, rc), '\n', '\n' ]) if log_file_object: with open(sub_log_filename) as sub_log_file_object: sub_log = sub_log_file_object.readlines() log_file_object.writelines(sub_log) return overall_return_code
def _set_qchem_memory(self, qcinp=None): if not qcinp: qcinp = QcInput.from_file(self.input_file) if "PBS_JOBID" in os.environ: if "hopque" in os.environ["PBS_JOBID"]: # on Hopper for j in qcinp.jobs: if self.current_command_name == "general": if self.large_static_mem: j.set_memory(total=1100, static=300) else: j.set_memory(total=1100, static=100) elif self.current_command_name == "half_cpus": if self.large_static_mem: j.set_memory(total=2200, static=500) else: j.set_memory(total=2200, static=100) elif self.current_command_name == "openmp": if self.large_static_mem: j.set_memory(total=28000, static=10000) else: j.set_memory(total=28000, static=3000) elif "NERSC_HOST" in os.environ and os.environ["NERSC_HOST"] == "cori": if "QCSCRATCH" in os.environ and "eg_qchem" in os.environ[ "QCSCRATCH"]: # in memory scratch for j in qcinp.jobs: if self.current_command_name == "general": if self.large_static_mem: j.set_memory(total=1400, static=200) else: j.set_memory(total=1500, static=100) elif self.current_command_name == "half_cpus": if self.large_static_mem: j.set_memory(total=3000, static=500) else: j.set_memory(total=3200, static=300) elif self.current_command_name == "openmp": if self.large_static_mem: j.set_memory(total=50000, static=12000) else: j.set_memory(total=60000, static=2000) else: # disk scratch for j in qcinp.jobs: if self.current_command_name == "general": if self.large_static_mem: j.set_memory(total=2700, static=500) else: j.set_memory(total=3000, static=200) elif self.current_command_name == "half_cpus": if self.large_static_mem: j.set_memory(total=6000, static=1000) else: j.set_memory(total=6500, static=500) elif self.current_command_name == "openmp": if self.large_static_mem: j.set_memory(total=100000, static=25000) else: j.set_memory(total=120000, static=8000) elif "NERSC_HOST" in os.environ and os.environ[ "NERSC_HOST"] == "edison": if "QCSCRATCH" in os.environ and "/tmp/eg_qchem" in os.environ[ "QCSCRATCH"]: # in memory scratch for j in qcinp.jobs: if self.current_command_name == "general": if self.large_static_mem: j.set_memory(total=1200, static=300) else: j.set_memory(total=1200, static=100) elif self.current_command_name == "half_cpus": if self.large_static_mem: j.set_memory(total=2400, static=400) else: j.set_memory(total=2400, static=200) elif self.current_command_name == "openmp": if self.large_static_mem: j.set_memory(total=25000, static=1000) else: j.set_memory(total=25000, static=500) else: # disk scratch for j in qcinp.jobs: if self.current_command_name == "general": if self.large_static_mem: j.set_memory(total=2500, static=500) else: j.set_memory(total=2500, static=100) elif self.current_command_name == "half_cpus": if self.large_static_mem: j.set_memory(total=5000, static=1000) else: j.set_memory(total=5000, static=200) elif self.current_command_name == "openmp": if self.large_static_mem: j.set_memory(total=60000, static=20000) else: j.set_memory(total=60000, static=5000) elif "NERSC_HOST" in os.environ and os.environ[ "NERSC_HOST"] == "matgen": if "QCSCRATCH" in os.environ and "eg_qchem" in os.environ[ "QCSCRATCH"]: # in memory scratch for j in qcinp.jobs: if self.current_command_name == "general": if self.large_static_mem: j.set_memory(total=1500, static=200) else: j.set_memory(total=1600, static=100) elif self.current_command_name == "half_cpus": if self.large_static_mem: j.set_memory(total=3000, static=600) else: j.set_memory(total=3200, static=400) elif self.current_command_name == "openmp": if self.large_static_mem: j.set_memory(total=15000, static=5500) else: j.set_memory(total=29000, static=2000) else: # disk scratch for j in qcinp.jobs: if self.current_command_name == "general": if self.large_static_mem: j.set_memory(total=2800, static=500) else: j.set_memory(total=3100, static=200) elif self.current_command_name == "half_cpus": if self.large_static_mem: j.set_memory(total=6000, static=1100) else: j.set_memory(total=6500, static=600) elif self.current_command_name == "openmp": if self.large_static_mem: j.set_memory(total=50000, static=10000) else: j.set_memory(total=59000, static=3000) elif 'vesta' in socket.gethostname(): for j in qcinp.jobs: j.set_memory(total=13500, static=800) qcinp.write_file(self.input_file)
def geom_fw(self, charge, spin_multiplicity, fw_id_cal, fw_id_db, priority=None, method=None, task_type_prefix=None): task_type = "geometry optimization" if task_type_prefix: task_type = task_type_prefix + " " + task_type state_name = self.get_state_name(charge, spin_multiplicity) if not method: if self.large: method = "PBE-D3/6-31+G*" else: method = "B3lYP/6-31+G*" title = self.molname + " " + state_name + " " + method + " " + task_type exchange, correlation, basis_set, aux_basis, rem_params, method_token, ecp = self. \ get_exchange_correlation_basis_auxbasis_remparams(method, self.mol) qctask = QcTask(self.mol, charge=charge, spin_multiplicity=spin_multiplicity, jobtype="opt", title=title, exchange=exchange, correlation=correlation, basis_set=basis_set, aux_basis_set=aux_basis, ecp=ecp, rem_params=rem_params) if self.large: qctask.set_geom_max_iterations(200) qctask.set_scf_algorithm_and_iterations(iterations=100) qctask.scale_geom_opt_threshold(gradient=1.0, displacement=10.0, energy=10.0) qcinp = QcInput([qctask]) spec = self.base_spec() spec["qcinp"] = qcinp.as_dict() spec['task_type'] = task_type spec['charge'] = charge spec['spin_multiplicity'] = spin_multiplicity spec['run_tags']['methods'] = method_token spec["qm_method"] = method if priority: spec['_priority'] = priority task_name = self.molname + ' ' + state_name + ' ' + task_type from rubicon.firetasks.qchem.multistep_qchem_task \ import QChemGeomOptDBInsertionTask fw_geom_cal = Firework([QChemTask()], spec=spec, name=task_name, fw_id=fw_id_cal) spec_db = copy.deepcopy(spec) del spec_db['_dupefinder'] spec_db['_allow_fizzled_parents'] = True spec_db['task_type'] = task_type + ' DB Insertion' del spec_db["_trackers"][:2] task_name_db = task_name + " DB Insertion" fw_geom_db = Firework([QChemGeomOptDBInsertionTask()], spec=spec_db, name=task_name_db, fw_id=fw_id_db) return fw_geom_cal, fw_geom_db
def _set_qchem_memory(self, qcinp=None): if not qcinp: qcinp = QcInput.from_file(self.input_file) if "PBS_JOBID" in os.environ: if "hopque" in os.environ["PBS_JOBID"]: # on Hopper for j in qcinp.jobs: if self.current_command_name == "general": if self.large_static_mem: j.set_memory(total=1100, static=300) else: j.set_memory(total=1100, static=100) elif self.current_command_name == "half_cpus": if self.large_static_mem: j.set_memory(total=2200, static=500) else: j.set_memory(total=2200, static=100) elif self.current_command_name == "openmp": if self.large_static_mem: j.set_memory(total=28000, static=10000) else: j.set_memory(total=28000, static=3000) elif "edique" in os.environ["PBS_JOBID"]: # on Edison if "QCSCRATCH" in os.environ and "/tmp/eg_qchem" in os.environ["QCSCRATCH"]: # in memory scratch for j in qcinp.jobs: if self.current_command_name == "general": if self.large_static_mem: j.set_memory(total=1200, static=300) else: j.set_memory(total=1200, static=100) elif self.current_command_name == "half_cpus": if self.large_static_mem: j.set_memory(total=2400, static=400) else: j.set_memory(total=2400, static=200) elif self.current_command_name == "openmp": if self.large_static_mem: j.set_memory(total=25000, static=1000) else: j.set_memory(total=25000, static=500) else: # disk scratch for j in qcinp.jobs: if self.current_command_name == "general": if self.large_static_mem: j.set_memory(total=2500, static=500) else: j.set_memory(total=2500, static=100) elif self.current_command_name == "half_cpus": if self.large_static_mem: j.set_memory(total=5000, static=1000) else: j.set_memory(total=5000, static=200) elif self.current_command_name == "openmp": if self.large_static_mem: j.set_memory(total=60000, static=20000) else: j.set_memory(total=60000, static=5000) elif "NERSC_HOST" in os.environ and os.environ["NERSC_HOST"] == "cori": if "QCSCRATCH" in os.environ and "eg_qchem" in os.environ["QCSCRATCH"]: # in memory scratch for j in qcinp.jobs: if self.current_command_name == "general": if self.large_static_mem: j.set_memory(total=1400, static=200) else: j.set_memory(total=1500, static=100) elif self.current_command_name == "half_cpus": if self.large_static_mem: j.set_memory(total=3000, static=500) else: j.set_memory(total=3200, static=300) elif self.current_command_name == "openmp": if self.large_static_mem: j.set_memory(total=50000, static=12000) else: j.set_memory(total=60000, static=2000) else: # disk scratch for j in qcinp.jobs: if self.current_command_name == "general": if self.large_static_mem: j.set_memory(total=2700, static=500) else: j.set_memory(total=3000, static=200) elif self.current_command_name == "half_cpus": if self.large_static_mem: j.set_memory(total=6000, static=1000) else: j.set_memory(total=6500, static=500) elif self.current_command_name == "openmp": if self.large_static_mem: j.set_memory(total=100000, static=25000) else: j.set_memory(total=120000, static=8000) elif "NERSC_HOST" in os.environ and os.environ["NERSC_HOST"] == "matgen": if "QCSCRATCH" in os.environ and "eg_qchem" in os.environ["QCSCRATCH"]: # in memory scratch for j in qcinp.jobs: if self.current_command_name == "general": if self.large_static_mem: j.set_memory(total=1500, static=200) else: j.set_memory(total=1600, static=100) elif self.current_command_name == "half_cpus": if self.large_static_mem: j.set_memory(total=3000, static=600) else: j.set_memory(total=3200, static=400) elif self.current_command_name == "openmp": if self.large_static_mem: j.set_memory(total=15000, static=5500) else: j.set_memory(total=29000, static=2000) else: # disk scratch for j in qcinp.jobs: if self.current_command_name == "general": if self.large_static_mem: j.set_memory(total=2800, static=500) else: j.set_memory(total=3100, static=200) elif self.current_command_name == "half_cpus": if self.large_static_mem: j.set_memory(total=6000, static=1100) else: j.set_memory(total=6500, static=600) elif self.current_command_name == "openmp": if self.large_static_mem: j.set_memory(total=50000, static=10000) else: j.set_memory(total=59000, static=3000) elif 'vesta' in socket.gethostname(): for j in qcinp.jobs: j.set_memory(total=13500, static=800) qcinp.write_file(self.input_file)
def main(): import argparse parser = argparse.ArgumentParser( description="Run A QChem Job for a QChem Input File") parser.add_argument("-i", "--input", dest="input", type=str, required=True, help="the QChem output file with imaginary frequency") parser.add_argument("-o", "--output", dest="output", type=str, required=True, help="the QChem input file with perturbed geometry") parser.add_argument("-s", "--scale", dest="scale", type=float, default=0.3, help="the scale factor to perturb molecule") parser.add_argument("-r", "--reverse", dest="reverse", action="store_true", help="use reversed direction to perturb molecule") parser.add_argument("-v", "--verbose", dest="verbose", action="store_true", help="print parameters") options = parser.parse_args() qcout = QcOutput(options.input) charge = None spin_multiplicity = None for d in qcout.data: j = d["input"] if j.charge is not None: charge = j.charge if j.spin_multiplicity is not None: spin_multiplicity = j.spin_multiplicity if qcout.data[-1]['frequencies'][0]["frequency"] < -0.00: old_mol = qcout.data[-1]["molecules"][-1] vib_mode = qcout.data[-1]['frequencies'][0]["vib_mode"] if options.verbose: if options.reverse: direction_text = "User forward direction" else: direction_text = "User reversed direction" print("{} with scale factor {}".format(direction_text, options.scale)) new_mol = perturb_molecule(old_mol, vib_mode, reversed_direction=options.reverse, perturb_scale=options.scale) qctask_freq = qcout.data[-1]["input"] qctask_freq.mol = "read" qctask_freq.charge = charge qctask_freq.spin_multiplicity = spin_multiplicity qctask_opt = copy.deepcopy(qctask_freq) qctask_opt.params["rem"]["jobtype"] = "opt" qctask_opt.params["rem"].pop("scf_guess", None) qctask_opt.mol = new_mol qcinp = QcInput([qctask_opt, qctask_freq]) qcinp.write_file(options.output) else: raise ValueError( "Must have an imaginary frequency to perturb the molecule")
def test_assign_basis_set_by_range(self): qcinp_file_name = os.path.join(test_dir, "MgTFSI_31_acetonitrile.qcinp") basis_def_file_name = os.path.join(test_dir, "MgTFSI_31_AN_basis.txt") qcinp_no_basis = QcInput.from_file(qcinp_file_name) qcinp_with_basis = assign_basis_set_by_range( qcinp=qcinp_no_basis, basis_def_file=basis_def_file_name) self.assertEqual(qcinp_with_basis.jobs[0].params["rem"]["basis"], "mixed") ans = [('Mg', '3-21g*'), ('N', '3-21+g*'), ('S', '3-21+g*'), ('O', '3-21+g*'), ('O', '3-21+g*'), ('C', '3-21+g*'), ('F', '3-21+g*'), ('F', '3-21+g*'), ('F', '3-21+g*'), ('S', '3-21+g*'), ('O', '3-21+g*'), ('O', '3-21+g*'), ('C', '3-21+g*'), ('F', '3-21+g*'), ('F', '3-21+g*'), ('F', '3-21+g*'), ('C', '3-21g*'), ('C', '3-21g*'), ('N', '3-21+g*'), ('H', '3-21g*'), ('H', '3-21g*'), ('H', '3-21g*'), ('C', '3-21g*'), ('C', '3-21g*'), ('N', '3-21+g*'), ('H', '3-21g*'), ('H', '3-21g*'), ('H', '3-21g*'), ('C', '3-21g*'), ('C', '3-21g*'), ('N', '3-21+g*'), ('H', '3-21g*'), ('H', '3-21g*'), ('H', '3-21g*'), ('C', '3-21g*'), ('C', '3-21g*'), ('N', '3-21+g*'), ('H', '3-21g*'), ('H', '3-21g*'), ('H', '3-21g*'), ('C', '3-21g*'), ('C', '3-21g*'), ('N', '3-21+g*'), ('H', '3-21g*'), ('H', '3-21g*'), ('H', '3-21g*'), ('C', '3-21*'), ('C', '3-21*'), ('N', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('C', '3-21*'), ('C', '3-21*'), ('N', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('C', '3-21*'), ('C', '3-21*'), ('N', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('C', '3-21*'), ('C', '3-21*'), ('N', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('C', '3-21*'), ('C', '3-21*'), ('N', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('C', '3-21*'), ('C', '3-21*'), ('N', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('C', '3-21*'), ('C', '3-21*'), ('N', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('C', '3-21*'), ('C', '3-21*'), ('N', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('C', '3-21*'), ('C', '3-21*'), ('N', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('C', '3-21*'), ('C', '3-21*'), ('N', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('C', '3-21*'), ('C', '3-21*'), ('N', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('C', '3-21*'), ('C', '3-21*'), ('N', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('C', '3-21*'), ('C', '3-21*'), ('N', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('C', '3-21*'), ('C', '3-21*'), ('N', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('C', '3-21*'), ('C', '3-21*'), ('N', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('C', '3-21*'), ('C', '3-21*'), ('N', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('C', '3-21*'), ('C', '3-21*'), ('N', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('C', '3-21*'), ('C', '3-21*'), ('N', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('C', '3-21*'), ('C', '3-21*'), ('N', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('C', '3-21*'), ('C', '3-21*'), ('N', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('C', '3-21*'), ('C', '3-21*'), ('N', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('C', '3-21*'), ('C', '3-21*'), ('N', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('C', '3-21*'), ('C', '3-21*'), ('N', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('C', '3-21*'), ('C', '3-21*'), ('N', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('C', '3-21*'), ('C', '3-21*'), ('N', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('C', '3-21*'), ('C', '3-21*'), ('N', '3-21*'), ('H', '3-21*'), ('H', '3-21*'), ('H', '3-21*')] self.assertEqual(qcinp_with_basis.jobs[0].params["basis"], ans)
def sp_fw(self, charge, spin_multiplicity, fw_id_cal, fw_id_db, solvent_method="ief-pcm", use_vdw_surface=False, solvent="water", priority=None, qm_method=None, population_method=None, task_type_name=None): if not qm_method: qm_method = "B3LYP/6-31+G*" spec = self.base_spec() if priority: spec['_priority'] = priority task_type = task_type_name if task_type_name else "single point energy" state_name = self.get_state_name(charge, spin_multiplicity) title = self.molname + " " + state_name + " " + qm_method + " " + task_type title += "\n Gas Phase" exchange, correlation, basis_set, aux_basis, rem_params, method_token, ecp = self. \ get_exchange_correlation_basis_auxbasis_remparams(qm_method, self.mol) if population_method: if not rem_params: rem_params = dict() if population_method.lower() == "nbo": rem_params["nbo"] = 1 elif population_method.lower() == "chelpg": rem_params["chelpg"] = True qctask_vac = QcTask(self.mol, charge=charge, spin_multiplicity=spin_multiplicity, jobtype="sp", title=title, exchange=exchange, correlation=correlation, basis_set=basis_set, aux_basis_set=aux_basis, ecp=ecp, rem_params=rem_params) if not self.large: qctask_vac.set_dft_grid(128, 302) qctask_vac.set_integral_threshold(12) qctask_vac.set_scf_convergence_threshold(8) else: qctask_vac.set_scf_algorithm_and_iterations(iterations=100) title = " Solution Phase, {}".format(solvent) qctask_sol = QcTask(self.mol, charge=charge, spin_multiplicity=spin_multiplicity, jobtype="sp", title=title, exchange=exchange, correlation=correlation, basis_set=basis_set, aux_basis_set=aux_basis, ecp=ecp, rem_params=rem_params) qctask_sol.set_scf_initial_guess(guess="read") implicit_solvent = self.set_solvent_method(qctask_sol, solvent, solvent_method, use_vdw_surface) qcinp = QcInput([qctask_vac, qctask_sol]) spec["qcinp"] = qcinp.as_dict() spec['task_type'] = task_type spec['charge'] = charge spec['spin_multiplicity'] = spin_multiplicity spec['run_tags']['methods'] = method_token spec["qm_method"] = qm_method spec['implicit_solvent'] = implicit_solvent task_name = self.molname + ' ' + state_name + ' ' + task_type from rubicon.firetasks.qchem.multistep_qchem_task \ import QChemSinglePointEnergyDBInsertionTask fw_sp_cal = Firework([QChemTask()], spec=spec, name=task_name, fw_id=fw_id_cal) spec_db = copy.deepcopy(spec) del spec_db['_dupefinder'] spec_db['_allow_fizzled_parents'] = True spec_db['task_type'] = task_type + ' DB Insertion' del spec_db["_trackers"][:2] task_name_db = task_name + " DB Insertion" fw_sp_db = Firework([QChemSinglePointEnergyDBInsertionTask()], spec=spec_db, name=task_name_db, fw_id=fw_id_db) return fw_sp_cal, fw_sp_db
def aimd_fw(self, charge, spin_multiplicity, fw_id_cal, fw_id_db, num_steps, time_step, temperature, priority=None, qm_method=None): if not qm_method: qm_method = "B3LYP/6-31+G*" spec = self.base_spec() if priority: spec['_priority'] = priority task_type = "ab initio molecule dynamics" state_name = self.get_state_name(charge, spin_multiplicity) title = self.molname + " " + state_name + " " + qm_method + " " + task_type exchange, correlation, basis_set, aux_basis, rem_params, method_token, ecp = self. \ get_exchange_correlation_basis_auxbasis_remparams(qm_method, self.mol) if rem_params is None: rem_params = dict() rem_params["aimd_method"] = "bomd" rem_params["time_step"] = time_step rem_params["aimd_steps"] = num_steps rem_params["aimd_init_veloc"] = "thermal" rem_params["aimd_temp"] = temperature rem_params["fock_extrap_order"] = 6 rem_params["fock_extrap_points"] = 12 qctask_vac = QcTask(self.mol, charge=charge, spin_multiplicity=spin_multiplicity, jobtype="aimd", title=title, exchange=exchange, correlation=correlation, basis_set=basis_set, aux_basis_set=aux_basis, ecp=ecp, rem_params=rem_params) qctask_vac.set_scf_algorithm_and_iterations(iterations=100) qcinp = QcInput([qctask_vac]) spec["qcinp"] = qcinp.as_dict() spec['task_type'] = task_type spec['charge'] = charge spec['spin_multiplicity'] = spin_multiplicity spec['run_tags']['methods'] = method_token spec['run_tags']['rem_params'] = rem_params spec["qm_method"] = qm_method task_name = self.molname + ' ' + state_name + ' ' + task_type from rubicon.firetasks.qchem.multistep_qchem_task \ import QChemAIMDDBInsertionTask fw_sp_cal = Firework([QChemTask()], spec=spec, name=task_name, fw_id=fw_id_cal) spec_db = copy.deepcopy(spec) del spec_db['_dupefinder'] spec_db['_allow_fizzled_parents'] = True spec_db['task_type'] = task_type + ' DB Insertion' del spec_db["_trackers"][:2] task_name_db = task_name + " DB Insertion" fw_sp_db = Firework([QChemAIMDDBInsertionTask()], spec=spec_db, name=task_name_db, fw_id=fw_id_db) return fw_sp_cal, fw_sp_db
def vacuum_only_sp_fw(self, charge, spin_multiplicity, fw_id_cal, fw_id_db, priority=None, qm_method=None, population_method=None, mixed_basis_generator=None, mixed_aux_basis_generator=None, super_mol_snlgroup_id=None, super_mol_egsnl=None, super_mol_inchi_root=None, ghost_atoms=None, bs_overlap=False): if not qm_method: qm_method = "B3LYP/6-31+G*" spec = self.base_spec() if priority: spec['_priority'] = priority if super_mol_snlgroup_id: from rubicon.workflows.qchem.bsse_wf import BSSEFragment task_type = "bsse {} fragment".format( BSSEFragment.OVERLAPPED if bs_overlap else BSSEFragment. ISOLATED) else: task_type = "vacuum only single point energy" if mixed_basis_generator or mixed_aux_basis_generator: population_method = population_method if population_method else "nbo" task_type = "atomic charge" state_name = self.get_state_name(charge, spin_multiplicity) title = self.molname + " " + state_name + " " + qm_method + " " + task_type title += "\n Gas Phase" exchange, correlation, basis_set, aux_basis, rem_params, method_token, ecp = self. \ get_exchange_correlation_basis_auxbasis_remparams(qm_method, self.mol) if population_method: if not rem_params: rem_params = dict() if population_method.lower() == "nbo": rem_params["nbo"] = 1 elif population_method.lower() == "chelpg": rem_params["chelpg"] = True elif population_method.lower() == "hirshfeld": rem_params["hirshfeld"] = True ga = ghost_atoms if bs_overlap else None qctask_vac = QcTask(self.mol, charge=charge, spin_multiplicity=spin_multiplicity, jobtype="sp", title=title, exchange=exchange, correlation=correlation, basis_set=basis_set, aux_basis_set=aux_basis, ecp=ecp, rem_params=rem_params, ghost_atoms=ga) if (not self.large) and (mixed_basis_generator is None and mixed_aux_basis_generator is None): qctask_vac.set_dft_grid(128, 302) qctask_vac.set_integral_threshold(12) qctask_vac.set_scf_convergence_threshold(8) else: qctask_vac.set_scf_algorithm_and_iterations(iterations=100) qcinp = QcInput([qctask_vac]) spec["qcinp"] = qcinp.as_dict() spec['task_type'] = task_type spec['charge'] = charge spec['spin_multiplicity'] = spin_multiplicity spec['run_tags']['methods'] = method_token spec["qm_method"] = qm_method if super_mol_snlgroup_id: spec["run_tags"]["super_mol_snlgroup_id"] = super_mol_snlgroup_id spec["snlgroup_id"] = super_mol_snlgroup_id spec["egsnl"] = super_mol_egsnl spec["inchi_root"] = super_mol_inchi_root if ghost_atoms: spec["run_tags"]["ghost_atoms"] = sorted(set(ghost_atoms)) from rubicon.workflows.qchem.bsse_wf import BSSEFragment spec["run_tags"][ "bsse_fragment_type"] = BSSEFragment.OVERLAPPED if bs_overlap else BSSEFragment.ISOLATED if mixed_basis_generator: spec["_mixed_basis_set_generator"] = mixed_basis_generator if mixed_aux_basis_generator: spec["_mixed_aux_basis_set_generator"] = mixed_aux_basis_generator task_name = self.molname + ' ' + state_name + ' ' + task_type from rubicon.firetasks.qchem.multistep_qchem_task \ import QChemSinglePointEnergyDBInsertionTask fw_sp_cal = Firework([QChemTask()], spec=spec, name=task_name, fw_id=fw_id_cal) spec_db = copy.deepcopy(spec) del spec_db['_dupefinder'] spec_db['_allow_fizzled_parents'] = True spec_db['task_type'] = task_type + ' DB Insertion' del spec_db["_trackers"][:2] task_name_db = task_name + " DB Insertion" fw_sp_db = Firework([QChemSinglePointEnergyDBInsertionTask()], spec=spec_db, name=task_name_db, fw_id=fw_id_db) return fw_sp_cal, fw_sp_db
def _run_qchem_on_alcf(self, log_file_object=None): parent_qcinp = QcInput.from_file(self.input_file) njobs = len(parent_qcinp.jobs) return_codes = [] alcf_cmds = [] qc_jobids = [] for i, j in enumerate(parent_qcinp.jobs): qsub_cmd = copy.deepcopy(self.current_command) sub_input_filename = "alcf_{}_{}".format(i+1, self.input_file) sub_output_filename = "alcf_{}_{}".format(i+1, self.output_file) sub_log_filename = "alcf_{}_{}".format(i+1, self.qclog_file) qsub_cmd[-2] = sub_input_filename sub_qcinp = QcInput([copy.deepcopy(j)]) if "scf_guess" in sub_qcinp.jobs[0].params["rem"] and \ sub_qcinp.jobs[0].params["rem"]["scf_guess"] == "read": sub_qcinp.jobs[0].params["rem"].pop("scf_guess") if i > 0: if isinstance(j.mol, str) and j.mol == "read": prev_qcout_filename = "alcf_{}_{}".format(i+1-1, self.output_file) prev_qcout = QcOutput(prev_qcout_filename) prev_final_mol = prev_qcout.data[0]["molecules"][-1] j.mol = prev_final_mol sub_qcinp.write_file(sub_input_filename) logging.info("The command to run QChem is {}".format(' '.join(qsub_cmd))) alcf_cmds.append(qsub_cmd) p = subprocess.Popen(qsub_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = p.communicate() qc_jobid = int(out.strip()) qc_jobids.append(qc_jobid) cqwait_cmd = shlex.split("cqwait {}".format(qc_jobid)) subprocess.call(cqwait_cmd) output_file_name = "{}.output".format(qc_jobid) cobaltlog_file_name = "{}.cobaltlog".format(qc_jobid) with open(cobaltlog_file_name) as f: cobaltlog_last_line = f.readlines()[-1] exit_code_pattern = re.compile("an exit code of (?P<code>\d+);") m = exit_code_pattern.search(cobaltlog_last_line) if m: rc = float(m.group("code")) else: rc = -99999 return_codes.append(rc) for name_change_trial in range(10): if not os.path.exists(output_file_name): message = "{} is not found in {}, {}th wait " \ "for 5 mins\n".format( output_file_name, os.getcwd(), name_change_trial) logging.info(message) if log_file_object: log_file_object.writelines([message]) time.sleep(60 * 5) pass else: message = "Found qchem output file {} in {}, change file " \ "name\n".format(output_file_name, os.getcwd(), name_change_trial) logging.info(message) if log_file_object: log_file_object.writelines([message]) break log_file_object.flush() os.fsync(log_file_object.fileno()) shutil.move(output_file_name, sub_output_filename) shutil.move(cobaltlog_file_name, sub_log_filename) overall_return_code = min(return_codes) with open(self.output_file, "w") as out_file_object: for i, job_cmd, rc, qc_jobid in zip(range(njobs), alcf_cmds, return_codes, qc_jobids): sub_output_filename = "alcf_{}_{}".format(i+1, self.output_file) sub_log_filename = "alcf_{}_{}".format(i+1, self.qclog_file) with open(sub_output_filename) as sub_out_file_object: header_lines = ["Running Job {} of {} {}\n".format(i + 1, njobs, self.input_file), " ".join(job_cmd) + "\n"] if i > 0: header_lines = ['', ''] + header_lines sub_out = sub_out_file_object.readlines() out_file_object.writelines(header_lines) out_file_object.writelines(sub_out) if rc < 0 and rc != -99999: out_file_object.writelines(["Application {} exit codes: {}\n".format(qc_jobid, rc), '\n', '\n']) if log_file_object: with open(sub_log_filename) as sub_log_file_object: sub_log = sub_log_file_object.readlines() log_file_object.writelines(sub_log) return overall_return_code
def main(): import argparse parser = argparse.ArgumentParser( description="Run A QChem Job for a QChem Input File") parser.add_argument("-f", "--filename", dest="filename", type=str, required=True, help="the QChem input filename") parser.add_argument("-e", "--eliminate", dest="eli_img", action="store_true", help="whether to eliminate imaginary frequency") parser.add_argument("-b", "--mixed_basis", dest="mixed_basis", type=json.loads, required=False, help="The mixed basis as a dict") parser.add_argument("-a", "--mixed_aux_basis", dest="mixed_aux_basis", type=json.loads, required=False, help="The mixed auxiliary basis as a dict") parser.add_argument("-s", "--solvent", dest="solvent", type=str, required=False, help="the implicit solvent") parser.add_argument("-n", "--run_name", dest="run_name", type=str, default=None, help="the implicit solvent") options = parser.parse_args() call_qchem_task(options.filename, options.solvent, options.mixed_basis, options.mixed_aux_basis, run_name=options.run_name) if options.eli_img: base_filename = os.path.splitext(options.filename)[0] output_filename = base_filename + ".qcout" qcout = QcOutput(output_filename) charge = None spin_multiplicity = None for d in qcout.data: j = d["input"] if j.charge is not None: charge = j.charge if j.spin_multiplicity is not None: spin_multiplicity = j.spin_multiplicity if qcout.data[-1]['frequencies'][0]["frequency"] < -0.00: os.system("tar czvf img_freq_1.tar.gz *") old_mol = qcout.data[-1]["molecules"][-1] vib_mode = qcout.data[-1]['frequencies'][0]["vib_mode"] new_mol = perturb_molecule(old_mol, vib_mode) qctask_freq = qcout.data[-1]["input"] qctask_freq.mol = "read" qctask_freq.charge = charge qctask_freq.spin_multiplicity = spin_multiplicity qctask_opt = copy.deepcopy(qctask_freq) qctask_opt.params["rem"]["jobtype"] = "opt" qctask_opt.params["rem"].pop("scf_guess", None) qctask_opt.mol = new_mol qcinp = QcInput([qctask_opt, qctask_freq]) eli_file_1 = base_filename + "_eli_img_1.qcinp" qcinp.write_file(eli_file_1) call_qchem_task(eli_file_1, options.solvent, options.mixed_basis, options.mixed_aux_basis, run_name=options.run_name) output_filename = base_filename + "_eli_img_1.qcout" qcout = QcOutput(output_filename) if qcout.data[-1]['frequencies'][0]["frequency"] < -0.00: os.system("tar czvf img_freq_2.tar.gz *") old_mol = qcout.data[-1]["molecules"][-1] vib_mode = qcout.data[-1]['frequencies'][0]["vib_mode"] new_mol = perturb_molecule(old_mol, vib_mode) qctask_freq = qcout.data[-1]["input"] qctask_freq.mol = "read" qctask_freq.charge = charge qctask_freq.spin_multiplicity = spin_multiplicity qctask_opt = copy.deepcopy(qctask_freq) qctask_opt.params["rem"]["jobtype"] = "opt" qctask_opt.params["rem"].pop("scf_guess", None) qctask_opt.mol = new_mol qcinp = QcInput([qctask_opt, qctask_freq]) for j in qcinp.jobs: j.set_dft_grid(128, 302) j.set_integral_threshold(12) if j.params["rem"]["jobtype"] == "opt": j.scale_geom_opt_threshold(0.1, 0.1, 0.1) j.set_geom_max_iterations(100) eli_file_2 = base_filename + "_eli_img_2.qcinp" qcinp.write_file(eli_file_2) call_qchem_task(eli_file_2, options.solvent, options.mixed_basis, options.mixed_aux_basis, run_name=options.run_name) output_filename = base_filename + "_eli_img_2.qcout" qcout = QcOutput(output_filename) if qcout.data[-1]['frequencies'][0]["frequency"] < -0.00: os.system("tar czvf img_freq_3.tar.gz *") old_mol = qcout.data[-1]["molecules"][-1] vib_mode = qcout.data[-1]['frequencies'][0]["vib_mode"] new_mol = perturb_molecule(old_mol, vib_mode) qctask_freq = qcout.data[-1]["input"] qctask_freq.mol = "read" qctask_freq.charge = charge qctask_freq.spin_multiplicity = spin_multiplicity qctask_opt = copy.deepcopy(qctask_freq) qctask_opt.params["rem"]["jobtype"] = "opt" qctask_opt.params["rem"].pop("scf_guess", None) qctask_opt.mol = new_mol qcinp = QcInput([qctask_opt, qctask_freq]) for j in qcinp.jobs: j.set_dft_grid(90, 590) j.set_integral_threshold(12) if j.params["rem"]["jobtype"] == "opt": j.scale_geom_opt_threshold(0.1, 0.1, 0.1) j.set_geom_max_iterations(100) eli_file_3 = base_filename + "_eli_img_3.qcinp" qcinp.write_file(eli_file_3) call_qchem_task(eli_file_3, options.solvent, options.mixed_basis, options.mixed_aux_basis, run_name=options.run_name)