def bindCN(self, site_index, molecule, v, CN_bond_length=1.16, catC_bond_length=1.49): """ input: molecule: (molSimplify mol class) molecule to modify in-place with O2 v: (np.array) coordinates to displace first O output: molecule modified with functional group OH """ site_coords = molecule.atoms[site_index].coords() v_C = self.scale_vector(v, catC_bond_length) v_N = self.scale_vector(v, catC_bond_length + CN_bond_length) site_coords = molecule.atoms[site_index].coords() molecule.addAtom( mol3D.atom3D( Sym='C', xyz=[site_coords[c] + v_C[c] for c in range(len(site_coords))])) molecule.addAtom( mol3D.atom3D( Sym='N', xyz=[site_coords[c] + v_N[c] for c in range(len(site_coords))])) #structgen.ffopt('MMFF94', molecule, [], 1, [], False, [], 200, False) # keeps failing return molecule
def bindO2H(self, site_index, molecule, v, bond_angle=111., OO_bond_length=1.32, catO_bond_length=1.55): """ input: molecule: (molSimplify mol class) molecule to modify in-place with O2 v: (np.array) coordinates to displace first O output: molecule modified with functional group O2H """ site_coords = molecule.atoms[site_index].coords() v_O1 = self.scale_vector(v, catO_bond_length) v_O2 = self.scale_vector( v, catO_bond_length + OO_bond_length * math.cos(math.pi - math.radians(bond_angle))) v_H = self.scale_vector(v, self.OH_bond_length) theta_0 = 0 # arbitrarily chosen v_perp = self.vec3_perp( self.scale_vector( v, self.OO_bond_length * math.sin(math.pi - math.radians(bond_angle))), theta_0) if v_perp == None: # shouldn't happen return None site_coords = molecule.atoms[site_index].coords() molecule.addAtom( mol3D.atom3D(Sym='O', xyz=[ site_coords[c] + v_O1[c] for c in range(len(site_coords)) ])) molecule.addAtom( mol3D.atom3D(Sym='O', xyz=[ site_coords[c] + v_O2[c] + v_perp[c] for c in range(len(site_coords)) ])) molecule.addAtom( mol3D.atom3D(Sym='H', xyz=[ site_coords[c] + v_O2[c] + (v_perp[c] + v_H[c]) for c in range(len(site_coords)) ])) #structgen.ffopt('MMFF94', molecule, [], 1, [], False, [], 200, False) # keeps failing return molecule
def bind_OOH(infile, molecule, site_index, catO_bond_length, catOO_bond_angle, OO_bond_length, OH_bond_length): molecule_copy = mol3D.mol3D() molecule_copy.copymol3D(molecule) v = get_normal_vec(molecule_copy, site_index) v_O1 = scale_vector(v, catO_bond_length) v_O2 = scale_vector( v, catO_bond_length + OO_bond_length * math.cos(math.pi - math.radians(catOO_bond_angle))) theta_0 = 0 v_perp = vec3_perp( scale_vector( v, OO_bond_length * math.sin(math.pi - math.radians(catOO_bond_angle))), theta_0) if v_perp == None: # shouldn't happen return None v_H = scale_vector(v, OH_bond_length) site_coords = molecule_copy.atoms[site_index].coords() molecule_copy.addAtom( mol3D.atom3D( Sym='O', xyz=[site_coords[c] + v_O1[c] for c in range(len(site_coords))])) molecule_copy.addAtom( mol3D.atom3D(Sym='O', xyz=[ site_coords[c] + v_O2[c] + v_perp[c] for c in range(len(site_coords)) ])) molecule_copy.addAtom( mol3D.atom3D(Sym='H', xyz=[ site_coords[c] + v_O2[c] + v_perp[c] + v_H[c] for c in range(len(site_coords)) ])) file_name = infile.split('.')[0] + "OOH" if not is_metal_catalyst: # metal catalysts assumed to have one active site file_name += "-" + str(site_index) # still zero-indexed molecule_copy.writexyz(file_name)
def bind_O(infile, molecule, site_index, catO_bond_length): molecule_copy = mol3D.mol3D() molecule_copy.copymol3D(molecule) v = get_normal_vec(molecule_copy, site_index) v_O = scale_vector(v, catO_bond_length) site_coords = molecule_copy.atoms[site_index].coords() molecule_copy.addAtom( mol3D.atom3D( Sym='O', xyz=[site_coords[c] + v_O[c] for c in range(len(site_coords))])) file_name = infile.split('.')[0] + "O" if not is_metal_catalyst: # metal catalysts assumed to have one active site file_name += "-" + str(site_index) # still zero-indexed molecule_copy.writexyz(file_name)
oxo = mymol.getAtom(-1) oxo_coord = oxo.coords() metal_coord = mymol.getAtom(metalval[0]).coords() bond1_coord = mymol.getAtom(bondedatoms[0]).coords() bond2_coord = mymol.getAtom(bondedatoms[1]).coords() oxo, dxyz = setPdistance(oxo, oxo_coord, metal_coord, 1.84) metaloxo = np.array(oxo_coord) - np.array(metal_coord) extra = getPointu(oxo_coord, 1.2, metaloxo) moveup = np.array(extra) - metal_coord val = midpt(bond1_coord, bond2_coord) movevect = np.array( normalize( np.array(val) + moveup - np.array(oxo_coord))) + oxo_coord p = list(movevect) newH = atom3D('H', p) mymol.addAtom(newH) hydrogen = mymol.getAtom(-1) hydrogen, dxyz = setPdistance(hydrogen, hydrogen.coords(), oxo.coords(), 1) if not dry_run: if not os.path.exists( path_dictionary["initial_geo_path"] + modgeo1 ) and (upperspin in metal_spin_dictionary[metal][hydroxyl_ox]): mymol.writexyz( path_dictionary["initial_geo_path"] + modgeo1) elif (upperspin not in metal_spin_dictionary[metal] [hydroxyl_ox]): print((str(upperspin) + ' spin not in dictionary for ' +
def bind_O2(self, site_index, catO_bond_length=1.8, bond_angle=120, OO_bond_length=1.3, reposition_O2=False): # binds O2 perpendicular to catalyst plane, then makes .xyz file # does not modify input molecule # bond lengths in angstroms, angle in degrees. Variables set to parameters for Fe molecule_copy = mol3D.mol3D() molecule_copy.copymol3D(self.molecule) connection_list = molecule_copy.getBondedAtomsSmart(site_index, oct=False) #print("Active Site: %s Neighbors: %s" %(str(site_index), str(connection_list))) # for debugging try: v1 = molecule_copy.atoms[connection_list[0]].distancev( molecule_copy.atoms[connection_list[1]]) v2 = molecule_copy.atoms[connection_list[0]].distancev( molecule_copy.atoms[connection_list[2]]) v = np.cross(v1, v2) except: print("Error finding plane of catalyst.") return None v_O1 = self.scale_vector(v, catO_bond_length) v_O2 = self.scale_vector( v, catO_bond_length + OO_bond_length * math.cos(math.pi - math.radians(bond_angle))) theta_0 = 0 # arbitrarily chosen v_perp = self.vec3_perp( self.scale_vector( v, OO_bond_length * math.sin(math.pi - math.radians(bond_angle))), theta_0) if v_perp == None: # shouldn't happen return None site_coords = molecule_copy.atoms[site_index].coords() molecule_copy.addAtom( mol3D.atom3D(Sym='O', xyz=[ site_coords[c] + v_O1[c] for c in range(len(site_coords)) ])) molecule_copy.addAtom( mol3D.atom3D(Sym='O', xyz=[ site_coords[c] + v_O2[c] + v_perp[c] for c in range(len(site_coords)) ])) #structgen.ffopt('MMFF94', molecule_copy, [], 1, [], False, [], 200, False) # keeps failing if reposition_O2: # workaround for ffopt() failing to set up; nonmetal catalysts theta = theta_0 + self.dtheta position_OK = False while not position_OK: position_OK = True for atom in molecule_copy.getAtoms(): if atom == molecule_copy.getAtoms( )[-1] or atom == molecule_copy.getAtoms()[-2]: continue if atom.symbol() in self.bond_length_cutoffs: cutoff = self.bond_length_cutoffs[atom.symbol()] else: # won't happen if bond_length_cutoffs is kept up to date cutoff = self.bond_length_cutoffs[max( self.bond_length_cutoffs, key=lambda key: self.bond_length_cutoffs[key])] print("Using %f A as the bond length cutoff for %s" % (cutoff, atom.symbol())) if molecule_copy.getAtoms()[-1].distance(atom) < cutoff: position_OK = False break if not position_OK: if theta >= 360: print("%s may have geometry issues after O2-binding." % infile) break v_perp = self.vec3_perp( self.scale_vector( v, OO_bond_length * math.sin(math.pi - math.radians(bond_angle))), theta) if v_perp == None: # shouldn't happen return None molecule_copy.getAtoms()[-1].setcoords([ site_coords[c] + v_O2[c] + v_perp[c] for c in range(len(site_coords)) ]) theta += self.dtheta file_name = self.infile.split('.')[0] + "O2" if len(self.active_sites ) > 1: #only add active site in name if more than 1 file_name += "-" + str(site_index) # still zero-indexed molecule_copy.writexyz(file_name)
def bind_XY(infile, molecule, site_index, X, Y, catX_bond_length, bond_angle, XY_bond_length, reposition_XY, fn_suffix): # XY is any diatomic species, with X closer to the active site # positions XY perpendicular to catalyst plane, then makes .xyz file # does not modify input molecule # bond lengths in angstroms, angle in degrees molecule_copy = mol3D.mol3D() molecule_copy.copymol3D(molecule) v = get_normal_vec(molecule_copy, site_index) v_X = scale_vector(v, catX_bond_length) v_Y = scale_vector( v, catX_bond_length + XY_bond_length * math.cos(math.pi - math.radians(bond_angle))) theta_0 = 0 # arbitrarily chosen v_perp = vec3_perp( scale_vector( v, XY_bond_length * math.sin(math.pi - math.radians(bond_angle))), theta_0) if v_perp == None: # shouldn't happen return None site_coords = molecule_copy.atoms[site_index].coords() molecule_copy.addAtom( mol3D.atom3D( Sym=X, xyz=[site_coords[c] + v_X[c] for c in range(len(site_coords))])) molecule_copy.addAtom( mol3D.atom3D(Sym=Y, xyz=[ site_coords[c] + v_Y[c] + v_perp[c] for c in range(len(site_coords)) ])) #structgen.ffopt('MMFF94', molecule_copy, [], 1, [], False, [], 200, False) # keeps failing if reposition_XY: # workaround for ffopt() failing to set up; nonmetal catalysts bond_length_cutoffs = { 'C': 1.953, 'H': 1.443, 'I': 2.543, 'Cl': 2.154, 'B': 2.027, 'N': 1.834, 'F': 1.707, 'Br': 2.423, 'P': 2.297, 'S': 2.198, 'O': 1.810 } # X-O (angstroms) dtheta = 5 # change this if you want to theta = theta_0 + dtheta position_OK = False while not position_OK: position_OK = True for atom in molecule_copy.getAtoms(): if atom == molecule_copy.getAtoms( )[-1] or atom == molecule_copy.getAtoms()[-2]: continue if atom.symbol() in bond_length_cutoffs: cutoff = bond_length_cutoffs[atom.symbol()] else: # won't happen if bond_length_cutoffs is kept up to date cutoff = bond_length_cutoffs[max( bond_length_cutoffs, key=lambda key: bond_length_cutoffs[key])] print("Using %f A as the bond length cutoff for %s" % (cutoff, atom.symbol())) if molecule_copy.getAtoms()[-1].distance(atom) < cutoff: position_OK = False break if not position_OK: if theta >= 360: print("%s may have geometry issues after O2-binding." % infile) break v_perp = vec3_perp( scale_vector( v, XY_bond_length * math.sin(math.pi - math.radians(bond_angle))), theta) if v_perp == None: # shouldn't happen return None molecule_copy.getAtoms()[-1].setcoords([ site_coords[c] + v_Y[c] + v_perp[c] for c in range(len(site_coords)) ]) theta += dtheta file_name = infile.split('.')[0] + fn_suffix if not is_metal_catalyst: # metal catalysts assumed to have one active site file_name += "-" + str(site_index) # still zero-indexed molecule_copy.writexyz(file_name)