def set_geometry(self): print("Setting charge and spin in QM calculations : ", self.QMcharge, self.QMspin) if self.QMspin > 1: # set UKS core.set_local_option('SCF', 'REFERENCE', 'UKS') #*************** Add MM charges in QMregion for analytic embedding # these atoms are in QMother, which contains QMregion minus QMatoms Chrgfield = QMMM( ) # this class should be available with 'from psi4.driver import *' for atom in self.QMother: Chrgfield.extern.addCharge(atom.charge, atom.x, atom.y, atom.z) core.set_global_option_python('EXTERN', Chrgfield.extern) # construct geometry string geometrystring = ' \n ' geometrystring = geometrystring + str(self.QMcharge) + " " + str( self.QMspin) + " \n" # don't reorient molecule. Don't want symmetry anyway for DMA geometrystring = geometrystring + " noreorient \n " + " nocom \n " #**************** Input QMatoms/positions for QM calculation for atom in self.QMatoms: geometrystring = geometrystring + " " + str( atom.element) + " " + str(atom.x) + " " + str( atom.y) + " " + str(atom.z) + " \n" geometrystring = geometrystring + ' symmetry c1 \n ' # now create Psi4 geometry object self.geometry = psi4.geometry(geometrystring)
def electrostatic_embedding(metadata, pair): """ Add atom-centered point charges for fragments whose basis sets are not included in the computation. """ from psi4.driver import constants, qmmm if not metadata['return_total_data']: raise Exception('Cannot return interaction data when using embedding scheme.') # Add embedding point charges Chrgfield = qmmm.QMMMbohr() for p in metadata['embedding_charges']: if p in pair[1]: continue mol = metadata['molecule'].extract_subsets([p]) for i in range(mol.natom()): geom = np.array([mol.x(i), mol.y(i), mol.z(i)]) Chrgfield.extern.addCharge(metadata['embedding_charges'][p][i], geom[0], geom[1], geom[2]) core.set_global_option_python('EXTERN', Chrgfield.extern)
def psr_2_psi4_mol(PsrMol): """Converts the pulsar molecule into a Psi4 molecule TODO: Add symmetry """ mol_string="no_com\nno_reorient\nunits bohr\nsymmetry c1\n"\ +str(int(PsrMol.charge))+" "+str(int(PsrMol.multiplicity))\ +"\n" charges = QMMM() has_charges = False for atom in PsrMol: if not psr.is_point_charge(atom): mol_string+=psr.atomic_symbol_from_z(atom.Z)+" "+\ str(atom[0])+" "+str(atom[1])+" "+str(atom[2])+"\n" else: has_charges = True charges.extern.addCharge(atom.charge,atom[0],atom[1],atom[2]) if has_charges: psi4.set_global_option_python('EXTERN',charges.extern) return psi4.Molecule.create_molecule_from_string(mol_string)
def electrostatic_embedding(metadata, pair): """ Add atom-centered point charges for fragments whose basis sets are not included in the computation. """ from psi4.driver import qmmm from psi4.driver import constants if not metadata['return_total_data']: raise Exception('Cannot return interaction data when using embedding scheme.') # Add embedding point charges Chrgfield = qmmm.QMMM() for p in metadata['embedding_charges']: if p in pair[1]: continue mol = metadata['molecule'].extract_subsets([p]) for i in range(mol.natom()): geom = np.array([mol.x(i), mol.y(i), mol.z(i)]) if mol.units() == 'Angstrom': geom *= constants.bohr2angstroms Chrgfield.extern.addCharge(metadata['embedding_charges'][p][i], geom[0], geom[1], geom[2]) core.set_global_option_python('EXTERN', Chrgfield.extern)
def compute_nbody_components(func, method_string, metadata): """Computes requested N-body components. Performs requested computations for psi4::Molecule object `molecule` according to `compute_list` with function `func` at `method_string` level of theory. Parameters ---------- func : {'energy', 'gradient', 'hessian'} Function object to be called within N-Body procedure. method_string : str Indicates level of theory to be passed to function `func`. metadata : dict of str Dictionary of N-body metadata. Required ``'key': value`` pairs: ``'compute_list'``: dict of int: set List of computations to perform. Keys indicate body-levels, e.g,. `compute_list[2]` is the list of all 2-body computations required. ``'kwargs'``: dict Arbitrary keyword arguments to be passed to function `func`. Returns ------- dict of str: dict Dictionary containing computed N-body components. Contents: ``'energies'``: dict of set: float64 Dictionary containing all energy components required for given N-body procedure. ``'ptype'``: dict of set: float64 or dict of set: psi4.Matrix Dictionary of returned quantities from calls of function `func` during N-body computations ``'intermediates'``: dict of str: float64 Dictionary of psivars for intermediate N-body computations to be set at the end of the N-body procedure. """ # Get required metadata kwargs = metadata['kwargs'] molecule = metadata['molecule'] #molecule = core.get_active_molecule() compute_list = metadata['compute_dict']['all'] # Now compute the energies energies_dict = {} gradients_dict = {} ptype_dict = {} intermediates_dict = {} if kwargs.get('charge_method', False) and not metadata['embedding_charges']: metadata['embedding_charges'] = driver_nbody_helper.compute_charges(kwargs['charge_method'], kwargs.get('charge_type', 'MULLIKEN_CHARGES').upper(), molecule) for count, n in enumerate(compute_list.keys()): core.print_out("\n ==> N-Body: Now computing %d-body complexes <==\n\n" % n) total = len(compute_list[n]) for num, pair in enumerate(compute_list[n]): core.print_out( "\n N-Body: Computing complex (%d/%d) with fragments %s in the basis of fragments %s.\n\n" % (num + 1, total, str(pair[0]), str(pair[1]))) ghost = list(set(pair[1]) - set(pair[0])) current_mol = molecule.extract_subsets(list(pair[0]), ghost) current_mol.set_name("%s_%i_%i" % (current_mol.name(), count, num)) if metadata['embedding_charges']: driver_nbody_helper.electrostatic_embedding(metadata, pair=pair) # Save energies info ptype_dict[pair], wfn = func(method_string, molecule=current_mol, return_wfn=True, **kwargs) core.set_global_option_python('EXTERN', None) energies_dict[pair] = core.variable("CURRENT ENERGY") gradients_dict[pair] = wfn.gradient() var_key = "N-BODY (%s)@(%s) TOTAL ENERGY" % (', '.join([str(i) for i in pair[0]]), ', '.join( [str(i) for i in pair[1]])) intermediates_dict[var_key] = core.variable("CURRENT ENERGY") core.print_out("\n N-Body: Complex Energy (fragments = %s, basis = %s: %20.14f)\n" % (str( pair[0]), str(pair[1]), energies_dict[pair])) # Flip this off for now, needs more testing #if 'cp' in bsse_type_list and (len(bsse_type_list) == 1): # core.set_global_option('DF_INTS_IO', 'LOAD') core.clean() return { 'energies': energies_dict, 'gradients': gradients_dict, 'ptype': ptype_dict, 'intermediates': intermediates_dict }
def compute_nbody_components(func, method_string, metadata): """Computes requested N-body components. Performs requested computations for psi4::Molecule object `molecule` according to `compute_list` with function `func` at `method_string` level of theory. Parameters ---------- func : str {'energy', 'gradient', 'hessian'} Function object to be called within N-Body procedure. method_string : str Indicates level of theory to be passed to function `func`. metadata : dict of str Dictionary of N-body metadata. Required ``'key': value`` pairs: ``'compute_list'``: dict of int: set List of computations to perform. Keys indicate body-levels, e.g,. `compute_list[2]` is the list of all 2-body computations required. ``'kwargs'``: dict Arbitrary keyword arguments to be passed to function `func`. Returns ------- dict of str: dict Dictionary containing computed N-body components. Contents: ``'energies'``: dict of set: float64 Dictionary containing all energy components required for given N-body procedure. ``'ptype'``: dict of set: float64 or dict of set: psi4.Matrix Dictionary of returned quantities from calls of function `func` during N-body computations ``'intermediates'``: dict of str: float64 Dictionary of psivars for intermediate N-body computations to be set at the end of the N-body procedure. """ # Get required metadata kwargs = metadata['kwargs'] molecule = metadata['molecule'] #molecule = core.get_active_molecule() compute_list = metadata['compute_dict']['all'] # Now compute the energies energies_dict = {} gradients_dict = {} ptype_dict = {} intermediates_dict = {} if kwargs.get('charge_method', False) and not metadata['embedding_charges']: metadata['embedding_charges'] = driver_nbody_helper.compute_charges( kwargs['charge_method'], kwargs.get('charge_type', 'MULLIKEN_CHARGES').upper(), molecule) for count, n in enumerate(compute_list.keys()): core.print_out( "\n ==> N-Body: Now computing %d-body complexes <==\n\n" % n) total = len(compute_list[n]) for num, pair in enumerate(compute_list[n]): core.print_out( "\n N-Body: Computing complex (%d/%d) with fragments %s in the basis of fragments %s.\n\n" % (num + 1, total, str(pair[0]), str(pair[1]))) ghost = list(set(pair[1]) - set(pair[0])) current_mol = molecule.extract_subsets(list(pair[0]), ghost) current_mol.set_name("%s_%i_%i" % (current_mol.name(), count, num)) if metadata['embedding_charges']: driver_nbody_helper.electrostatic_embedding(metadata, pair=pair) # Save energies info ptype_dict[pair], wfn = func(method_string, molecule=current_mol, return_wfn=True, **kwargs) core.set_global_option_python('EXTERN', None) energies_dict[pair] = core.variable("CURRENT ENERGY") gradients_dict[pair] = wfn.gradient() var_key = "N-BODY (%s)@(%s) TOTAL ENERGY" % (', '.join( [str(i) for i in pair[0]]), ', '.join([str(i) for i in pair[1]])) intermediates_dict[var_key] = core.variable("CURRENT ENERGY") core.print_out( "\n N-Body: Complex Energy (fragments = %s, basis = %s: %20.14f)\n" % (str(pair[0]), str(pair[1]), energies_dict[pair])) # Flip this off for now, needs more testing #if 'cp' in bsse_type_list and (len(bsse_type_list) == 1): # core.set_global_option('DF_INTS_IO', 'LOAD') core.clean() return { 'energies': energies_dict, 'gradients': gradients_dict, 'ptype': ptype_dict, 'intermediates': intermediates_dict }