def test_FrequencyFlatteningOptimizeFW_defaults(self): firework = FrequencyFlatteningOptimizeFW(molecule=self.act_mol) self.assertEqual( firework.tasks[0].as_dict(), WriteInputFromIOSet(molecule=self.act_mol, qchem_input_set="OptSet", input_file="mol.qin", qchem_input_params={}).as_dict()) self.assertEqual( firework.tasks[1].as_dict(), RunQChemCustodian(qchem_cmd=">>qchem_cmd<<", multimode=">>multimode<<", input_file="mol.qin", output_file="mol.qout", max_cores=">>max_cores<<", job_type="opt_with_frequency_flattener", max_iterations=10, max_molecule_perturb_scale=0.3, reversed_direction=False).as_dict()) self.assertEqual( firework.tasks[2].as_dict(), QChemToDb(db_file=None, input_file="mol.qin", output_file="mol.qout", additional_fields={ "task_label": "frequency flattening structure optimization", "special_run_type": "frequency_flattener" }).as_dict()) self.assertEqual(firework.parents, []) self.assertEqual(firework.name, "frequency flattening structure optimization")
def get_wf_FFopt_and_critic(molecule, suffix, qchem_input_params=None, db_file=">>db_file<<", **kwargs): """ """ # FFopt fw1 = FrequencyFlatteningOptimizeFW( molecule=molecule, name="{}:{}".format(molecule.composition.alphabetical_formula, "FFopt_" + suffix), qchem_cmd=">>qchem_cmd<<", max_cores=">>max_cores<<", qchem_input_params=qchem_input_params, linked=True, db_file=">>db_file<<") # Critic fw2 = CubeAndCritic2FW(name="{}:{}".format( molecule.composition.alphabetical_formula, "CC2_" + suffix), qchem_cmd=">>qchem_cmd<<", max_cores=">>max_cores<<", qchem_input_params=qchem_input_params, db_file=">>db_file<<", parents=fw1) fws = [fw1, fw2] wfname = "{}:{}".format(molecule.composition.alphabetical_formula, "FFopt_CC2_WF_" + suffix) return Workflow(fws, name=wfname, **kwargs)
def _build_new_FWs(self): """ Build the list of new fireworks: a FrequencyFlatteningOptimizeFW for each unique fragment molecule, unless the fragment is a single atom, in which case add a SinglePointFW instead. If the fragment is already in the database, don't add any new firework. """ from atomate.qchem.fireworks.core import FrequencyFlatteningOptimizeFW from atomate.qchem.fireworks.core import SinglePointFW new_FWs = [] for ii, unique_molecule in enumerate(self.unique_molecules): if not self._in_database(unique_molecule): if len(unique_molecule) == 1: new_FWs.append( SinglePointFW( molecule=unique_molecule, name="fragment_" + str(ii), qchem_cmd=">>qchem_cmd<<", max_cores=">>max_cores<<", qchem_input_params=self.qchem_input_params, db_file=">>db_file<<")) else: new_FWs.append( FrequencyFlatteningOptimizeFW( molecule=unique_molecule, name="fragment_" + str(ii), qchem_cmd=">>qchem_cmd<<", max_cores=">>max_cores<<", qchem_input_params=self.qchem_input_params, linked=self.linked, db_file=">>db_file<<")) return new_FWs
def test_FrequencyFlatteningOptimizeFW_not_defaults(self): firework = FrequencyFlatteningOptimizeFW( molecule=self.act_mol, name="special frequency flattening structure optimization", qchem_cmd="qchem -slurm", multimode="mpi", max_cores=12, qchem_input_params={"pcm_dielectric": 10.0}, max_iterations=5, max_molecule_perturb_scale=0.2, linked=True, db_file=os.path.join(db_dir, "db.json"), parents=None, ) self.assertEqual( firework.tasks[0].as_dict(), WriteInputFromIOSet( molecule=self.act_mol, qchem_input_set="OptSet", input_file="mol.qin", qchem_input_params={ "pcm_dielectric": 10.0 }, ).as_dict(), ) self.assertEqual( firework.tasks[1].as_dict(), RunQChemCustodian( qchem_cmd="qchem -slurm", multimode="mpi", input_file="mol.qin", output_file="mol.qout", max_cores=12, job_type="opt_with_frequency_flattener", max_iterations=5, max_molecule_perturb_scale=0.2, linked=True, ).as_dict(), ) self.assertEqual( firework.tasks[2].as_dict(), QChemToDb( db_file=os.path.join(db_dir, "db.json"), input_file="mol.qin", output_file="mol.qout", additional_fields={ "task_label": "special frequency flattening structure optimization", "special_run_type": "frequency_flattener", "linked": True, }, ).as_dict(), ) self.assertEqual(firework.parents, []) self.assertEqual( firework.name, "special frequency flattening structure optimization")
def get_wf_double_FF_opt(molecule, pcm_dielectric, max_cores=32, qchem_input_params=None, name="douple_FF_opt", qchem_cmd=">>qchem_cmd<<", db_file=">>db_file<<", **kwargs): """ Returns a workflow to the torsion potential for a molecule. Firework 1 : write QChem input for an FF optimization, run FF_opt QCJob, parse directory and insert into db, pass relaxed molecule to fw_spec and on to fw2, Firework 2 : write QChem input for an optimization in the presence of a PCM, using the molecule passed from fw1, run FF_opt QCJob, parse directory and insert into db Args: molecule (Molecule): input molecule to be optimized and run. pcm_dielectric (float): The PCM dielectric constant. max_cores (int): Maximum number of cores to parallelize over. Defaults to 32. qchem_input_params (dict): Specify kwargs for instantiating the input set parameters. qchem_cmd (str): Command to run QChem. db_file (str): path to file containing the database credentials. kwargs (keyword arguments): additional kwargs to be passed to Workflow Returns: Workflow """ first_qchem_input_params = qchem_input_params or {} # Optimize the molecule in vacuum fw1 = FrequencyFlatteningOptimizeFW( molecule=molecule, name="first_FF_no_pcm", qchem_cmd=qchem_cmd, max_cores=max_cores, qchem_input_params=first_qchem_input_params, db_file=db_file) # Optimize the molecule in PCM second_qchem_input_params = {"pcm_dielectric": pcm_dielectric} for key in first_qchem_input_params: second_qchem_input_params[key] = first_qchem_input_params[key] fw2 = FrequencyFlatteningOptimizeFW( name="second_FF_with_pcm", qchem_cmd=qchem_cmd, max_cores=max_cores, qchem_input_params=second_qchem_input_params, db_file=db_file, parents=fw1) fws = [fw1, fw2] wfname = "{}:{}".format(molecule.composition.reduced_formula, name) return Workflow(fws, name=wfname, **kwargs)
def get_fragmentation_wf(molecule, depth=1, open_rings=True, additional_charges=None, do_triplets=True, pcm_dielectric=None, do_optimization=True, linked=False, qchem_input_params=None, name="FF then fragment", db_file=">>db_file<<", check_db=True, **kwargs): """ Args: molecule (Molecule): input molecule to be fragmented. depth (int): The number of levels of iterative fragmentation to perform, where each evel will include fragments obtained by breaking one bond of a fragment one level up. If set to 0, instead all possible fragments are generated using an alternative, non-iterative scheme. Defaults to 1. open_rings (bool): Whether or not to open any rings encountered during fragmentation. Defaults to True. If true, any bond that fails to yield disconnected graphs when broken is instead removed and the entire structure is optimized with OpenBabel in order to obtain a good initial guess for an opened geometry that can then be put back into QChem to be optimized without the ring just reforming. additional_charges (list): List of additional charges besides the defaults described in the firetask. For example, if a principle molecule with a +2 charge is provided, by default all fragments will be calculated with +1 and +2 charges. If the user includes additional_charges=[0] then all fragments will be calculated with 0, +1, and +2 charges. Additional charge values of 1 or 2 would not cause any new charges to be calculated as they are already done. Defaults to []. do_triplets (bool): Whether to simulate triplets as well as singlets for molecules with an even number of electrons. Defaults to True. pcm_dielectric (float): The PCM dielectric constant. do_optimization (bool): Whether or not to optimize the given molecule before fragmentation. Defaults to True. qchem_input_params (dict): Specify kwargs for instantiating the input set parameters. Basic uses would be to modify the default inputs of the set, such as dft_rung, basis_set, pcm_dielectric, scf_algorithm, or max_scf_cycles. See pymatgen/io/qchem/sets.py for default values of all input parameters. For instance, if a user wanted to use a more advanced DFT functional, include a pcm with a dielectric of 30, and use a larger basis, the user would set qchem_input_params = {"dft_rung": 5, "pcm_dielectric": 30, "basis_set": "6-311++g**"}. However, more advanced customization of the input is also possible through the overwrite_inputs key which allows the user to directly modify the rem, pcm, smd, and solvent dictionaries that QChemDictSet passes to inputs.py to print an actual input file. For instance, if a user wanted to set the sym_ignore flag in the rem section of the input file to true, then they would set qchem_input_params = {"overwrite_inputs": "rem": {"sym_ignore": "true"}}. Of course, overwrite_inputs could be used in conjuction with more typical modifications, as seen in the test_double_FF_opt workflow test. db_file (str): path to file containing the database credentials. check_db (bool): Whether or not to check the database for equivalent structures before adding new fragment fireworks. Defaults to True. kwargs (keyword arguments): additional kwargs to be passed to Workflow Returns: Workflow with the following fireworks: Firework 1 : write QChem input for an FF optimization, run FF_opt QCJob, parse directory and insert into db, pass relaxed molecule to fw_spec and on to fw2, Firework 2 : find all unique fragments of the optimized molecule and add a frequency flattening optimize FW to the workflow for each one Note that Firework 1 is only present if do_optimization=True. """ qchem_input_params = qchem_input_params or {} additional_charges = additional_charges or [] if pcm_dielectric != None: qchem_input_params["pcm_dielectric"] = pcm_dielectric if do_optimization: # Optimize the original molecule fw1 = FrequencyFlatteningOptimizeFW( molecule=molecule, name="first FF", qchem_cmd=">>qchem_cmd<<", max_cores=">>max_cores<<", qchem_input_params=qchem_input_params, linked=linked, db_file=db_file) # Fragment the optimized molecule fw2 = FragmentFW(depth=depth, open_rings=open_rings, additional_charges=additional_charges, do_triplets=do_triplets, linked=linked, name="fragment and FF_opt", qchem_input_params=qchem_input_params, db_file=db_file, check_db=check_db, parents=fw1) fws = [fw1, fw2] else: # Fragment the given molecule fw1 = FragmentFW(molecule=molecule, depth=depth, open_rings=open_rings, additional_charges=additional_charges, do_triplets=do_triplets, linked=linked, name="fragment and FF_opt", qchem_input_params=qchem_input_params, db_file=db_file, check_db=check_db) fws = [fw1] wfname = "{}:{}".format(molecule.composition.reduced_formula, name) return Workflow(fws, name=wfname, **kwargs)
def get_wf_FFopt_and_critic(molecule, suffix, qchem_input_params=None, db_file=">>db_file<<", **kwargs): """ Firework 1 : write QChem input for an FF optimization, run FF_opt QCJob, parse directory and insert into db, pass relaxed molecule to fw_spec and on to fw2, Firework 2 : write QChem input for a single point calc to print a cube file run SP QCJob, thereby printing a cube file run Critic2 on the printed cube file parse directory and insert into db Args: molecule (Molecule): input molecule to be optimized and run. suffix (str): Workflow naming suffix qchem_input_params (dict): Specify kwargs for instantiating the input set parameters. Basic uses would be to modify the default inputs of the set, such as dft_rung, basis_set, pcm_dielectric, scf_algorithm, or max_scf_cycles. See pymatgen/io/qchem/sets.py for default values of all input parameters. For instance, if a user wanted to use a more advanced DFT functional, include a pcm with a dielectric of 30, and use a larger basis, the user would set qchem_input_params = {"dft_rung": 5, "pcm_dielectric": 30, "basis_set": "6-311++g**"}. However, more advanced customization of the input is also possible through the overwrite_inputs key which allows the user to directly modify the rem, pcm, smd, and solvent dictionaries that QChemDictSet passes to inputs.py to print an actual input file. For instance, if a user wanted to set the sym_ignore flag in the rem section of the input file to true, then they would set qchem_input_params = {"overwrite_inputs": "rem": {"sym_ignore": "true"}}. Of course, overwrite_inputs could be used in conjuction with more typical modifications, as seen in the test_double_FF_opt workflow test. db_file (str): path to file containing the database credentials. kwargs (keyword arguments): additional kwargs to be passed to Workflow Returns: Workflow """ qchem_input_params = qchem_input_params or {} # FFopt fw1 = FrequencyFlatteningOptimizeFW( molecule=molecule, name="{}:{}".format(molecule.composition.alphabetical_formula, "FFopt_" + suffix), qchem_cmd=">>qchem_cmd<<", max_cores=">>max_cores<<", qchem_input_params=qchem_input_params, linked=True, db_file=">>db_file<<", ) # Critic fw2 = CubeAndCritic2FW( name="{}:{}".format(molecule.composition.alphabetical_formula, "CC2_" + suffix), qchem_cmd=">>qchem_cmd<<", max_cores=">>max_cores<<", qchem_input_params=qchem_input_params, db_file=">>db_file<<", parents=fw1, ) fws = [fw1, fw2] wfname = "{}:{}".format(molecule.composition.alphabetical_formula, "FFopt_CC2_WF_" + suffix) return Workflow(fws, name=wfname, **kwargs)
def get_wf_double_FF_opt(molecule, pcm_dielectric, max_cores=">>max_cores<<", qchem_input_params=None, name="douple_FF_opt", qchem_cmd=">>qchem_cmd<<", db_file=">>db_file<<", **kwargs): """ Firework 1 : write QChem input for an FF optimization, run FF_opt QCJob, parse directory and insert into db, pass relaxed molecule to fw_spec and on to fw2, Firework 2 : write QChem input for an optimization in the presence of a PCM, using the molecule passed from fw1, run FF_opt QCJob, parse directory and insert into db Args: molecule (Molecule): input molecule to be optimized and run. pcm_dielectric (float): The PCM dielectric constant. max_cores (int): Maximum number of cores to parallelize over. Defaults to 32. qchem_input_params (dict): Specify kwargs for instantiating the input set parameters. Basic uses would be to modify the default inputs of the set, such as dft_rung, basis_set, pcm_dielectric, scf_algorithm, or max_scf_cycles. See pymatgen/io/qchem/sets.py for default values of all input parameters. For instance, if a user wanted to use a more advanced DFT functional, include a pcm with a dielectric of 30, and use a larger basis, the user would set qchem_input_params = {"dft_rung": 5, "pcm_dielectric": 30, "basis_set": "6-311++g**"}. However, more advanced customization of the input is also possible through the overwrite_inputs key which allows the user to directly modify the rem, pcm, smd, and solvent dictionaries that QChemDictSet passes to inputs.py to print an actual input file. For instance, if a user wanted to set the sym_ignore flag in the rem section of the input file to true, then they would set qchem_input_params = {"overwrite_inputs": "rem": {"sym_ignore": "true"}}. Of course, overwrite_inputs could be used in conjuction with more typical modifications, as seen in the test_double_FF_opt workflow test. qchem_cmd (str): Command to run QChem. db_file (str): path to file containing the database credentials. kwargs (keyword arguments): additional kwargs to be passed to Workflow Returns: Workflow """ first_qchem_input_params = qchem_input_params or {} # Optimize the molecule in vacuum fw1 = FrequencyFlatteningOptimizeFW( molecule=molecule, name="first_FF_no_pcm", qchem_cmd=qchem_cmd, max_cores=max_cores, qchem_input_params=first_qchem_input_params, db_file=db_file) # Optimize the molecule in PCM second_qchem_input_params = {"pcm_dielectric": pcm_dielectric} for key in first_qchem_input_params: second_qchem_input_params[key] = first_qchem_input_params[key] fw2 = FrequencyFlatteningOptimizeFW( name="second_FF_with_pcm", qchem_cmd=qchem_cmd, max_cores=max_cores, qchem_input_params=second_qchem_input_params, db_file=db_file, parents=fw1) fws = [fw1, fw2] wfname = "{}:{}".format(molecule.composition.reduced_formula, name) return Workflow(fws, name=wfname, **kwargs)