def harvest(in_mol: Molecule, nwout: str, **kwargs) -> Tuple[PreservingDict, None, list, Molecule, str, str]: """Parses all the pieces of output from NWChem: the stdout in *nwout* Scratch files are not yet considered at this moment. Args: in_mol (Molecule): Input molecule nwout (str): NWChem output molecule Returns: - (PreservingDict) Variables extracted from the output file in the last complete step - (None): Hessian from the last complete step (Not yet implemented) - (list): Gradient from the last complete step - (Molecule): Molecule from the last complete step - (str): Version string - (str): Error message, if any """ # Parse the NWChem output outPsivar, outMol, outGrad, version, error = harvest_output(nwout) # Make sure the input and output molecules are the same if outMol: if in_mol: if abs(outMol.nuclear_repulsion_energy() - in_mol.nuclear_repulsion_energy()) > 1.0e-3: raise ValueError( """NWChem outfile (NRE: %f) inconsistent with Psi4 input (NRE: %f).""" % (outMol.nuclear_repulsion_energy(), in_mol.nuclear_repulsion_energy()) ) else: raise ValueError("""No coordinate information extracted from NWChem output.""") return outPsivar, None, outGrad, outMol, version, error
def harvest(in_mol: Molecule, nwout: str, **outfiles) -> Tuple[PreservingDict, None, list, Molecule, str, str]: """Parses all the pieces of output from NWChem: the stdout in *nwout* Scratch files are not yet considered at this moment. Args: in_mol (Molecule): Input molecule nwout (str): NWChem output molecule outfiles (dict): Dictionary of outfile files and their contents Returns: - (PreservingDict) Variables extracted from the output file in the last complete step - (None): Hessian from the last complete step (Not yet implemented) - (list): Gradient from the last complete step - (Molecule): Molecule from the last complete step - (str): Version string - (str): Error message, if any """ # Parse the NWChem output out_psivar, out_mol, out_grad, version, error = harvest_output(nwout) # If available, read higher-accuracy gradients # These were output using a Python Task in NWChem to read them out of the database if outfiles.get("nwchem.grad") is not None: logger.debug("Reading higher-accuracy gradients") out_grad = json.loads(outfiles.get("nwchem.grad")) # If available, read the hessian out_hess = None if outfiles.get("nwchem.hess") is not None: out_hess = harvest_hessian(outfiles.get("nwchem.hess")) # Make sure the input and output molecules are the same if out_mol: if in_mol: if abs(out_mol.nuclear_repulsion_energy() - in_mol.nuclear_repulsion_energy()) > 1.0e-3: raise ValueError( """NWChem outfile (NRE: %f) inconsistent with Psi4 input (NRE: %f).""" % (out_mol.nuclear_repulsion_energy(), in_mol.nuclear_repulsion_energy()) ) else: raise ValueError("""No coordinate information extracted from NWChem output.""") # If present, align the gradients and hessian with the original molecular coordinates # NWChem rotates the coordinates of the input molecule. `out_mol` contains the coordinates for the # rotated molecule, which we can use to determine how to rotate the gradients/hessian amol, data = out_mol.align(in_mol, atoms_map=False, mols_align=True, verbose=0) mill = data["mill"] # Retrieve tool with alignment routines if out_grad is not None: out_grad = mill.align_gradient(np.array(out_grad).reshape(-1, 3)) if out_hess is not None: out_hess = mill.align_hessian(np.array(out_hess)) return out_psivar, out_hess, out_grad, out_mol, version, error
def harvest( in_mol: Molecule, method: str, gamessout: str, **outfiles ) -> Tuple[PreservingDict, Optional[np.ndarray], Optional[np.ndarray], Molecule]: """Parses all the pieces of output from gamess: the stdout in *gamessout* Scratch files are not yet considered at this moment. """ qcvars, calc_mol, calc_grad, module = harvest_output(gamessout) datasections = {} if outfiles.get("gamess.dat"): datasections = harvest_datfile(outfiles["gamess.dat"]) calc_hess = None if "$HESS" in datasections: calc_hess = load_hessian(datasections["$HESS"], dtype="gamess") if np.count_nonzero(calc_hess) == 0: calc_hess = None # Sometimes the hierarchical setting of CURRENT breaks down if method == "ccsd+t(ccsd)": qcvars["CURRENT CORRELATION ENERGY"] = qcvars["CCSD+T(CCSD) CORRELATION ENERGY"] qcvars["CURRENT ENERGY"] = qcvars["CCSD+T(CCSD) TOTAL ENERGY"] if calc_mol: qcvars["NUCLEAR REPULSION ENERGY"] = str(round(calc_mol.nuclear_repulsion_energy(), 8)) if in_mol: if abs(calc_mol.nuclear_repulsion_energy() - in_mol.nuclear_repulsion_energy()) > 1.0e-3: raise ValueError( f"""GAMESS outfile (NRE: {calc_mol.nuclear_repulsion_energy()}) inconsistent with AtomicInput.molecule (NRE: {in_mol.nuclear_repulsion_energy()}).""" ) # Frame considerations # * `in_mol` built with deliberation and with all fields accessible. # * `calc_mol` has the internally consistent geometry frame but otherwise dinky (geom & symbols & maybe chgmult). if in_mol.fix_com and in_mol.fix_orientation: # Impose input frame if important as signalled by fix_*=T return_mol = in_mol _, data = calc_mol.align(in_mol, atoms_map=False, mols_align=True, run_mirror=True, verbose=0) mill = data["mill"] else: return_mol, _ = in_mol.align(calc_mol, atoms_map=False, mols_align=True, run_mirror=True, verbose=0) mill = qcel.molutil.compute_scramble( len(in_mol.symbols), do_resort=False, do_shift=False, do_rotate=False, do_mirror=False ) # identity AlignmentMill return_grad = None if calc_grad is not None: return_grad = mill.align_gradient(calc_grad) return_hess = None if calc_hess is not None: return_hess = mill.align_hessian(np.array(calc_hess)) else: raise ValueError("""No coordinate information extracted from gamess output.""") return qcvars, return_hess, return_grad, return_mol, module
def _compute(self, driver): logger = logging.getLogger(__name__) logger.info("UserComputer only returning provided values") E = self.external_energy gX = self.external_gradient HX = self.external_hessian if driver == "hessian": if HX is None or gX is None or E is None: raise OptError("Must provide hessian, gradient, and energy.") elif driver == "gradient": if gX is None or E is None: raise OptError("Must provide gradient and energy.") elif driver == "energy": if E is None: raise OptError("Must provide energy.") result = deepcopy(UserComputer.output_skeleton) result["driver"] = driver mol = Molecule(**self.molecule) result["molecule"] = mol NRE = mol.nuclear_repulsion_energy() result["properties"]["nuclear_repulsion_energy"] = NRE result["extras"]["qcvars"]["NUCLEAR REPULSION ENERGY"] = NRE result["properties"]["return_energy"] = E result["extras"]["qcvars"]["CURRENT ENERGY"] = E if driver in ["gradient", "hessian"]: result["extras"]["qcvars"]["CURRENT GRADIENT"] = gX if driver == "hessian": result["extras"]["qcvars"]["CURRENT HESSIAN"] = HX if driver == "energy": result["return_result"] = E elif driver == "gradient": result["return_result"] = gX elif driver == "hessian": result["return_result"] = HX # maybe do this to protect against repeatedly going back for same? self.external_energy = None self.external_gradient = None self.external_hessian = None return AtomicResult(**result)
def harvest( in_mol: Molecule, method: str, gamessout: str, **outfiles ) -> Tuple[PreservingDict, Optional[np.ndarray], Optional[np.ndarray], Molecule]: """Parses all the pieces of output from gamess: the stdout in *gamessout* Scratch files are not yet considered at this moment. """ qcvars, calc_mol, calc_grad, module = harvest_output(gamessout) # Sometimes the hierarchical setting of CURRENT breaks down if method == "ccsd+t(ccsd)": qcvars["CURRENT CORRELATION ENERGY"] = qcvars[ "CCSD+T(CCSD) CORRELATION ENERGY"] qcvars["CURRENT ENERGY"] = qcvars["CCSD+T(CCSD) TOTAL ENERGY"] if calc_mol: qcvars["NUCLEAR REPULSION ENERGY"] = str( round(calc_mol.nuclear_repulsion_energy(), 8)) if in_mol: if abs(calc_mol.nuclear_repulsion_energy() - in_mol.nuclear_repulsion_energy()) > 1.0e-3: raise ValueError( f"""GAMESS outfile (NRE: {calc_mol.nuclear_repulsion_energy()}) inconsistent with AtomicInput.molecule (NRE: {in_mol.nuclear_repulsion_energy()}).""" ) return_mol = calc_mol amol, data = calc_mol.align(in_mol, atoms_map=False, mols_align=True, verbose=0) mill = data["mill"] return_grad = None if calc_grad is not None: return_grad = mill.align_gradient(calc_grad) return_hess = None else: raise ValueError( """No coordinate information extracted from gamess output.""") return qcvars, return_hess, return_grad, return_mol, module
def test_get_fragment(group_fragments, orient): mol = Molecule( **{ "fragments": [[0], [1, 2, 3], [4, 5, 6]], "symbols": ["he", "o", "h", "h", "o", "h", "h"], # same geom as test_water_orient but with He at origin "geometry": np.array([ [0.0, 0.0, 0.0], [-1.551007, -0.114520, 0.000000], [-1.934259, 0.762503, 0.000000], [-0.599677, 0.040712, 0.000000], [-0.114520, -1.551007, 10.000000], [0.762503, -1.934259, 10.000000], [0.040712, -0.599677, 10.000000], ]) / qcel.constants.bohr2angstroms, }) assert mol.nelectrons() == 22 assert compare_values(32.25894779318589, mol.nuclear_repulsion_energy(), atol=1.0e-5) assert mol.symbols[0] == "He" monomers_nelectrons = [2, 10, 10] monomers_nre = [0.0, 9.163830150548483, 9.163830150548483] monomers = [ mol.get_fragment(ifr, group_fragments=group_fragments, orient=orient) for ifr in range(3) ] for fr in range(3): assert monomers[fr].nelectrons() == monomers_nelectrons[fr] assert compare_values(monomers[fr].nuclear_repulsion_energy(), monomers_nre[fr], "monomer nre", atol=1.0e-5) idimers = [(0, 1), (0, 2), (1, 2), (1, 0), (2, 0), (2, 1)] dimers_nelectrons = [12, 12, 20, 12, 12, 20] dimers_nre = [ 16.8777971, 10.2097206, 23.4990904, 16.8777971, 10.2097206, 23.4990904 ] dimers = [ mol.get_fragment(rl, group_fragments=group_fragments, orient=orient) for rl in idimers ] for ifr in range(len(idimers)): # print('dd', ifr, idimers[ifr], dimers[ifr].nuclear_repulsion_energy(), dimers[ifr].get_hash()) assert dimers[ifr].nelectrons( ) == dimers_nelectrons[ifr], "dimer nelec" assert compare_values(dimers[ifr].nuclear_repulsion_energy(), dimers_nre[ifr], "dimer nre", atol=1.0e-5) if group_fragments and orient: assert dimers[0].get_hash() != dimers[3].get_hash( ) # atoms out of order assert dimers[1].get_hash() != dimers[4].get_hash( ) # atoms out of order assert dimers[2].get_hash() == dimers[5].get_hash() elif not group_fragments and not orient: assert dimers[0].get_hash() == dimers[3].get_hash() assert dimers[1].get_hash() == dimers[4].get_hash() assert dimers[2].get_hash() == dimers[5].get_hash() else: assert 0 # lgtm: [py/unreachable-statement] ghdimers_nelectrons = [2, 2, 10, 10, 10, 10] ghdimers_nre = [ 0.0, 0.0, 9.163830150548483, 9.163830150548483, 9.163830150548483, 9.163830150548483 ] ghdimers = [ mol.get_fragment(rl, gh, group_fragments=group_fragments, orient=orient) for rl, gh in idimers ] for ifr in range(len(idimers)): # print('gh', ifr, idimers[ifr], ghdimers[ifr].nuclear_repulsion_energy(), ghdimers[ifr].get_hash()) assert ghdimers[ifr].nelectrons( ) == ghdimers_nelectrons[ifr], "gh dimer nelec" assert compare_values(ghdimers[ifr].nuclear_repulsion_energy(), ghdimers_nre[ifr], "gh dimer nre", atol=1.0e-5) if group_fragments and orient: assert ghdimers[0].get_hash() != ghdimers[3].get_hash( ) # diff atoms ghosted assert ghdimers[1].get_hash() != ghdimers[4].get_hash( ) # diff atoms ghosted assert ghdimers[2].get_hash() == ghdimers[5].get_hash() elif not group_fragments and not orient: assert ghdimers[0].get_hash() != ghdimers[3].get_hash( ) # diff atoms ghosted assert ghdimers[1].get_hash() != ghdimers[4].get_hash( ) # diff atoms ghosted assert ghdimers[2].get_hash() != ghdimers[5].get_hash( ) # real pattern different assert not np.allclose(ghdimers[2].real, ghdimers[5].real) else: assert 0 # lgtm: [py/unreachable-statement]
def harvest(in_mol: Molecule, outfiles) -> Tuple[PreservingDict, None, None, Molecule, str, str]: """Parses all the pieces of output from Madness: the stdout in *nwout* Scratch files are not yet considered at this moment. Args: in_mol (Molecule): Input molecule madout (str): Madness output molecule outfiles (dict): Dictionary of outfile files and their contents Returns: - (PreservingDict) Variables extracted from the output file in the last complete step - (None): Hessian from the last complete step (Not yet implemented) - (None): Gradient from the last complete step (Not yet implemented) - (Molecule): Molecule from the last complete step - (str): Version string - (str): Error message, if any """ out_psivar = PreservingDict() # Parse the Madness output # This is a weird unpacking but i'm sure i'll find a more elegant way to do this later moldft_info = outfiles.get("moldft") moldft_outfiles = moldft_info.get("outfiles") # At this point scf prints a list of json outputs where each list refers to the scf at givin protocol # Here I load the scf_info and calc_info as json scf_info = json.loads(moldft_outfiles.get("scf_info.json")) calc_info = json.loads(moldft_outfiles.get("calc_info.json")) # Write harvest scf_info and harvest calc_info out_calc_vars = harvest_calc_info(calc_info) out_scf_vars = harvest_scf_info(scf_info) out_psivar.update(out_calc_vars) out_psivar.update(out_scf_vars) if "molresponse" in outfiles.keys(): molresponse_info = outfiles.get("moldft") molresponse_outfiles = molresponse_info.get("outfiles") # At this point scf prints a list of json outputs where each list refers to the scf at given protocol # Here I load the scf_info and calc_info as json response_info = json.loads(molresponse_outfiles.get("respones.json")) response_params, response_data_dict = read_molrespone_json(response_info) Idontneed_vars, out_mol, out_grad, version, error = harvest_moldft_output(outfiles["moldft"]["stdout"]) if "molresponse" in outfiles.keys(): response_psi_var = harvest_response_file(outfiles["molresponse"]["stdout"]) out_psivar.update(response_psi_var) # If available, read higher-accuracy gradients # These were output using a Python Task in Madness to read them out of the database if outfiles.get("mad.grad") is not None: logger.debug("Reading higher-accuracy gradients") out_grad = json.loads(outfiles.get("mad.grad")) # If available, read the hessian # TODO read in the geometry outputs from a geometry optimization # out_mol = None out_hess = None if outfiles.get("mad.hess") is not None: out_hess = harvest_hessian(outfiles.get("mad.hess")) # Make sure the input and output molecules are the same if out_mol: if in_mol: if abs(out_mol.nuclear_repulsion_energy() - in_mol.nuclear_repulsion_energy()) > 1.0e-3: raise ValueError( """Madness outfile (NRE: %f) inconsistent with MADNESS input (NRE: %f).""" % (out_mol.nuclear_repulsion_energy(), in_mol.nuclear_repulsion_energy()) ) # else: # raise ValueError("""No coordinate information extracted from Madness output.""") # If present, align the gradients and hessian with the original molecular coordinates # Madness rotates the coordinates of the input molecule. `out_mol` contains the coordinates for the # rotated molecule, which we can use to determine how to rotate the gradients/hessian # amol, data = out_mol.align(in_mol, atoms_map=False, mols_align=True, verbose=0) # mill = data["mill"] # Retrieve tool with alignment routines # if out_grad is not None: # out_grad = mill.align_gradient(np.array(out_grad).reshape(-1, 3)) # if out_hess is not None: # out_hess = mill.align_hessian(np.array(out_hess)) # TODO create a madness json that outputs basic info like the version and github hash? return out_psivar, out_hess, out_grad, out_mol, version, error