def lonepair(xcc, lNH2): lps = {} for X, torsion1, torsion2 in lNH2: phi1 = fncs.dihedral(*(xcc[3 * at:3 * at + 3] for at in torsion1)) phi2 = fncs.dihedral(*(xcc[3 * at:3 * at + 3] for at in torsion2)) phi = tfh.lonepair_dihedrals_from_phis(phi1, phi2) lps[X] = phi return lps
def assign_torsions(dcorr, graph1, graph2, xcc1, xcc2, symbols): ''' only one at a time ''' # number of non-assigned (initial) na_i = get_not_assigned(dcorr) # assignment based in proper torsions minad = float("inf") minnode1 = None minnode2 = None for node2, nodes1 in dcorr.items(): if type(nodes1) == int: continue BC = None # check neighbors atA2, atB2, atC2, atD2 = node2, None, None, None for atB2 in graph2.neighbors(atA2): if type(dcorr[atB2]) != int: continue for atC2 in graph2.neighbors(atB2): if type(dcorr[atC2]) != int: continue for neigh in graph2.neighbors(atC2): if type(dcorr[neigh]) != int: continue if len(set([atA2, atB2, atC2, neigh])) != 4: continue atD2 = neigh break if atD2 is not None: break if atD2 is not None: break # torsion located? if atD2 is None: continue # Now, check A-B-C-D atoms2 = [atA2, atB2, atC2, atD2] xs2 = (xcc2[3 * at:3 * at + 3] for at in atoms2) angle2 = np.rad2deg(fncs.dihedral(*xs2)) % 360 config2 = angle2 < 180 # compare torsions for node1 in nodes1: atoms1 = [node1, dcorr[atB2], dcorr[atC2], dcorr[atD2]] xs1 = (xcc1[3 * at:3 * at + 3] for at in atoms1) angle1 = np.rad2deg(fncs.dihedral(*xs1)) # difference ad = fncs.angular_dist(-angle2, angle1, u="deg") if ad < minad: minad = ad minnode1 = node1 minnode2 = node2 # Any new assignation to do?? if minnode1 is None: return dcorr, na_i # assign dcorr[minnode2] = minnode1 # number of non-assigned(final) dcorr, na_j = assign_check(dcorr) # return data if na_j != 0 and na_j != na_i: return assign_concatenate(dcorr, graph1, graph2) else: return assign_check(dcorr)
def lonepair_dihedral_from_xs(xN, xH1, xH2, xB, xA): ''' A-B-NH2 return dihedral A-B-N-lp, lp being the lone pair ''' # dihedral A-B-N-H1 phi1 = fncs.dihedral(xA, xB, xN, xH1) # dihedral A-B-N-H2 phi2 = fncs.dihedral(xA, xB, xN, xH2) # dihedral A-B-N-lp return lonepair_dihedrals_from_phis(phi1, phi2)
def assign_cx3(dcorr, graph1, graph2, xcc1, xcc2, symbols): # number of non-assigned (initial) na_i = get_not_assigned(dcorr) # Assign in CX3 groups (CH3, CF3, CCl3, et cetera) for node2, nodes1 in dcorr.items(): if type(nodes1) == int: continue if len(nodes1) != 3: continue neighbors2 = graph2.neighbors(node2) atC = neighbors2.pop() # check we have a C atom if len(neighbors2) != 0: continue if symbols[atC] != "C": continue # determine torsion X-C-B-A atA = None #print("*",node2+1,atC+1) for atB in graph2.neighbors(atC): if type(dcorr[atB]) != int: continue for neigh in graph2.neighbors(atB): if type(dcorr[neigh]) != int: continue if neigh == node2: continue if neigh == atC: continue atA = neigh #print(" ",atB+1,atA+1) break if atA is not None: break if atA is None: continue # calculate dihedral atoms2 = [node2, atC, atB, atA] #print([i+1 for i in atoms2]) xs2 = (xcc2[3 * at:3 * at + 3] for at in atoms2) angle2 = np.rad2deg(fncs.dihedral(*xs2)) # compare with the others minad = float("inf") minnode = None for node1 in nodes1: atoms1 = [node1, dcorr[atC], dcorr[atB], dcorr[atA]] xs1 = (xcc1[3 * at:3 * at + 3] for at in atoms1) angle1 = np.rad2deg(fncs.dihedral(*xs1)) # difference ad = fncs.angular_dist(-angle2, angle1, u="deg") if ad < minad: minad = ad minnode = node1 # apply dcorr[node2] = minnode # number of non-assigned(final) dcorr, na_j = assign_check(dcorr) # return data if na_j != 0 and na_j != na_i: return assign_concatenate(dcorr, graph1, graph2) else: return assign_check(dcorr)
def assign_via_improper_case1(dcorr,graph_0,graph_t,xcc_0,xcc_t): ''' C D correlation between A1, A2, ..., An \ / A1 - B - An in this situation, B, C and D / \ are assigned so Ai-B-C-D improper A2 ... torsion can be used ''' # number of non-assigned (initial) na_i = get_num_of_not_assigned(dcorr) # Compare spatial organization (improper torsions) for node_t,nodes_0 in dcorr.items(): if type(nodes_0) == int: continue # check neighbors atB2,atC2,atD2 = None,None,None for neigh in graph_t.neighbors(node_t): if type(dcorr[neigh]) != int: continue atB2,atC2,atD2 = neigh,None,None for nneigh in graph_t.neighbors(atB2): #print(node_t+1,neigh+1,nneigh+1) if nneigh == node_t: continue if type(dcorr[nneigh]) != int: continue if atC2 is None: atC2 = nneigh; continue if atD2 is None: atD2 = nneigh; break if atD2 is not None: break if atD2 is None: continue # now check spatial configuration atoms_t = [node_t,atB2,atC2,atD2] xs_t = (xcc_t[3*at:3*at+3] for at in atoms_t) angle_t = np.rad2deg(fncs.dihedral(*xs_t))%360 dcorr[node_t] = set([]) # correlate to closest one mindist, minnode = float("inf"),None for node_0 in nodes_0: atoms_0 = [node_0,dcorr[atB2],dcorr[atC2],dcorr[atD2]] xs_0 = (xcc_0[3*at:3*at+3] for at in atoms_0) angle_0 = np.rad2deg(fncs.dihedral(*xs_0))%360 dist = fncs.angular_dist(angle_0,angle_t,u="deg") if dist < mindist: mindist = dist minnode = node_0 dcorr[node_t] = minnode # break to avoid assign same node break # number of non-assigned(final) dcorr,na_j = assign_check(dcorr) # do again? if na_i != na_j and na_j != 0: dcorr = assign_via_improper_case1(dcorr,graph_0,graph_t,xcc_0,xcc_t)[0] # return data return assign_concatenate(dcorr,graph_0,graph_t)
def assign_pyramid(dcorr,graph_0,graph_t,symbols_0,symbols_t,xcc_0,xcc_t): ''' A1 B1 | B2 A2 X1 --> X1 or X2? \ / \ / X1 | X2 Ai!=Bi!=Ci!=Di / \ / \ C1 D1 | D2 C2 ''' for X_t,nodes_0 in dcorr.items(): if type(nodes_0) == int: continue if len(nodes_0) != 2 : continue neighbors_t = graph_t.neighbors(X_t) # number of neighbors nn_t = len(neighbors_t) if nn_t not in [3,4]: continue # check all neghbors are different nsymbols_t = len(set([symbols_t[idx] for idx in neighbors_t])) if nsymbols_t != nn_t: continue # sort neighbors by symbol neighbors_t = sorted(neighbors_t, key=lambda idx:symbols_t[idx]) # dihedral A-B-C-D or X-A-B-C? if nn_t == 4: atoms_t = neighbors_t else : atoms_t = [X_t]+list(neighbors_t) # calculate dihedral xs_t = (xcc_t[3*at:3*at+3] for at in atoms_t) angle_t = np.rad2deg(fncs.dihedral(*xs_t))%360 confi_t = angle_t > 180 # Check same distribution toremove = [] for X_0 in nodes_0: neighbors_0 = graph_0.neighbors(X_0) nn_0 = len(neighbors_0) if nn_0 != nn_t: continue # assert they are different nsymbols_0 = len(set([symbols_0[idx] for idx in neighbors_0])) if nsymbols_0 != nn_0: continue # sort neighbors by symbol neighbors_0 = sorted(neighbors_0, key=lambda idx:symbols_0[idx]) # dihedral A-B-C-D or X-A-B-C? if nn_0 == 4: atoms_0 = neighbors_0 else : atoms_0 = [X_0]+list(neighbors_0) # calculate dihedral xs_0 = (xcc_0[3*at:3*at+3] for at in atoms_0) angle_0 = np.rad2deg(fncs.dihedral(*xs_0))%360 confi_0 = angle_0 > 180 if confi_0 != confi_t: toremove.append(X_0) # remove for X_0 in toremove: nodes_0.remove(X_0) dcorr[X_t] = nodes_0 # return data return assign_concatenate(dcorr,graph_0,graph_t)
def test_hsconstraints(lzmat, zmatvals, constr, which="hard"): if constr is None or len(constr) == 0: return True # the xcc xcc = None # check constraints for ic, icdomain in constr: if ic in zmatvals: icvalue = zmatvals[ic] if icvalue < 0.0: icvalue = icvalue % 360 else: # Get atoms icatoms = [int(at) - 1 for at in ic.split("-")] nicatoms = len(icatoms) # Get xcc for each atom if xcc is None: xcc = intl.zmat2xcc(lzmat, zmatvals) xyzs = [fncs.xyz(xcc, at) for at in icatoms] # calculate value in xcc if nicatoms == 2: icvalue = fncs.distance(*xyzs) * ANGSTROM elif nicatoms == 3: icvalue = np.rad2deg(fncs.angle(*xyzs)) % 360 elif nicatoms == 4: icvalue = np.rad2deg(fncs.dihedral(*xyzs)) % 360 else: raise Exception # in domain? boolean = fncs.float_in_domain(icvalue, icdomain) if which == "hard" and boolean is False: return False if which == "soft" and boolean is True: return True # (hard) all of them are fulfilled if which == "hard": return True # (soft) all of them failed if which == "soft": return False
def correct_NH2_inversion(lzmat, zmatvals, zmatatoms, lNH2): inversion = False if len(lNH2) != 0: # Create Cartesian coords xcc0 = intl.zmat2xcc(lzmat, zmatvals) # Check every NH2 group for HNRH_atoms, HNRH_value, HNRH_bool in lNH2: # check inversion cvalue, cbool = deal_with_HNRH(HNRH_atoms, xcc0) if HNRH_bool == cbool: continue # EXCHANGE HIDROGEN ATOMS!! inversion = True idxH1 = HNRH_atoms[0] idxH2 = HNRH_atoms[3] x1 = xcc0[3 * idxH1:3 * idxH1 + 3] x2 = xcc0[3 * idxH2:3 * idxH2 + 3] xcc0[3 * idxH1:3 * idxH1 + 3] = x2 xcc0[3 * idxH2:3 * idxH2 + 3] = x1 # recalculate zmatrix values (only those involving H1 or H2) for ic, atoms in zmatatoms.items(): if not (idxH1 in atoms or idxH2 in atoms): continue xs = (xcc0[3 * at:3 * at + 3] for at in atoms) if len(atoms) == 2: zmatvals[ic] = ANGSTROM * fncs.distance(*xs) if len(atoms) == 3: zmatvals[ic] = np.rad2deg(fncs.angle(*xs)) if len(atoms) == 4: zmatvals[ic] = np.rad2deg(fncs.dihedral(*xs)) return zmatvals, inversion
def deal_with_HNRH(HNRH_atoms, xcc): ''' HNRH_atoms --> idxH1, idxN, idxR, idxH2 idxH1: index for first H atom idxN : index for N atom idxR : index for R group idxH2: index for second H atom ''' HNRH_value = fncs.dihedral(*(xcc[3 * at:3 * at + 3] for at in HNRH_atoms)) HNRH_bool = np.rad2deg(HNRH_value) % 360 < 180 return HNRH_value, HNRH_bool
def assign_spatial(dcorr, graph1, graph2, xcc1, xcc2, symbols): # number of non-assigned (initial) na_i = get_not_assigned(dcorr) # Compare spatial organization (improper torsions) for node2, nodes1 in dcorr.items(): if type(nodes1) == int: continue BC = None # check neighbors atB2, atC2, atD2 = None, None, None for neigh in graph2.neighbors(node2): if type(dcorr[neigh]) != int: continue atB2 = neigh atC2, atD2 = None, None for nneigh in graph2.neighbors(atB2): #print(node2+1,neigh+1,nneigh+1) if nneigh == node2: continue if type(dcorr[nneigh]) != int: continue if atC2 is None: atC2 = nneigh continue if atD2 is None: atD2 = nneigh break if atD2 is not None: break if atC2 is not None: BC = (atB2, atC2) # now check spatial configuration if atD2 is not None: atoms2 = [node2, atB2, atC2, atD2] xs2 = (xcc2[3 * at:3 * at + 3] for at in atoms2) angle2 = np.rad2deg(fncs.dihedral(*xs2)) % 360 config2 = angle2 < 180 dcorr[node2] = set([]) #print("*",node2+1,[i+1 for i in atoms2],angle2) for node1 in nodes1: atoms1 = [node1, dcorr[atB2], dcorr[atC2], dcorr[atD2]] xs1 = (xcc1[3 * at:3 * at + 3] for at in atoms1) angle1 = np.rad2deg(fncs.dihedral(*xs1)) % 360 config1 = angle1 < 180 #print("*",node1+1,[i+1 for i in atoms1],angle1) if config1 == config2: dcorr[node2].add(node1) #print() elif BC is not None and len(nodes1) == 2: atB2, atC2 = BC # look for the other node with same assigments in graph1 node2a = node2 node2b = None for node2_, nodes1_ in dcorr.items(): if node2_ == node2a: continue if nodes1 != nodes1_: continue node2b = node2_ break if node2b is None: continue # assert both nodes are connected to the same atoms!! if graph2.neighbors(node2a) != graph2.neighbors(node2b): continue # config in graph2 atoms2 = [node2a, node2b, atB2, atC2] xs2 = (xcc2[3 * at:3 * at + 3] for at in atoms2) angle2 = np.rad2deg(fncs.dihedral(*xs2)) % 360 config2 = angle2 < 180 # config in graph1 node1a, node1b = nodes1 atoms1 = [node1a, node1b, dcorr[atB2], dcorr[atC2]] xs1 = (xcc1[3 * at:3 * at + 3] for at in atoms1) angle1 = np.rad2deg(fncs.dihedral(*xs1)) % 360 config1 = angle1 < 180 if config1 == config2: dcorr[node2a] = node1a dcorr[node2b] = node1b else: dcorr[node2a] = node1b dcorr[node2b] = node1a # number of non-assigned(final) dcorr, na_j = assign_check(dcorr) # return data if na_j != 0 and na_j != na_i: return assign_concatenate(dcorr, graph1, graph2) else: return assign_check(dcorr)
def dihedral(self, at1, at2, at3, at4): x1 = self._xcc[3 * at1:3 * at1 + 3] x2 = self._xcc[3 * at2:3 * at2 + 3] x3 = self._xcc[3 * at3:3 * at3 + 3] x4 = self._xcc[3 * at4:3 * at4 + 3] return fncs.dihedral(x1, x2, x3, x4)
def assign_via_improper_case2(dcorr,graph_0,graph_t,xcc_0,xcc_t): ''' C D correlation between A1 & A2 \ / B in this situation, B, C are / \ assigned, but D is not! A1 A2 Assignation is done via A1-B-C-A2 ''' # number of non-assigned (initial) na_i = get_num_of_not_assigned(dcorr) # Compare spatial organization (improper torsions) for node_t,nodes_0 in dcorr.items(): if type(nodes_0) == int: continue if len(nodes_0) != 2 : continue BC = None # check neighbors atB2,atC2,atD2 = None,None,None for neigh in graph_t.neighbors(node_t): if type(dcorr[neigh]) != int: continue atB2,atC2,atD2 = neigh,None,None for nneigh in graph_t.neighbors(atB2): #print(node_t+1,neigh+1,nneigh+1) if nneigh == node_t: continue if type(dcorr[nneigh]) != int: continue if atC2 is None: atC2 = nneigh; continue if atD2 is None: atD2 = nneigh; break if atD2 is not None: break if atC2 is not None: BC = (atB2,atC2) # assert D is not assigned if atD2 is not None: continue # assert B and C are assigned if BC is None: continue # Unpack atB2,atC2 = BC # look for the other node with same assigments in graph_0 node_ta = node_t node_tb = None for node_t_,nodes_0_ in dcorr.items(): if node_t_ == node_ta : continue if nodes_0 != nodes_0_: continue node_tb = node_t_ break if node_tb is None: continue # assert both nodes are connected to the same atoms!! if graph_t.neighbors(node_ta) != graph_t.neighbors(node_tb): continue # config in graph_t atoms2 = [node_ta,node_tb,atB2,atC2] xs2 = (xcc_t[3*at:3*at+3] for at in atoms2) angle2 = np.rad2deg(fncs.dihedral(*xs2))%360 config2 = angle2 < 180 # config in graph_0 node_0a,node_0b = nodes_0 atoms1 = [node_0a,node_0b,dcorr[atB2],dcorr[atC2]] xs1 = (xcc_0[3*at:3*at+3] for at in atoms1) angle1 = np.rad2deg(fncs.dihedral(*xs1))%360 config1 = angle1 < 180 if config1 == config2: dcorr[node_ta] = node_0a dcorr[node_tb] = node_0b else: dcorr[node_ta] = node_0b dcorr[node_tb] = node_0a # number of non-assigned(final) dcorr,na_j = assign_check(dcorr) # return data return assign_concatenate(dcorr,graph_0,graph_t)
def xcc2vec(xcc, inpvars): phis = [] for X in inpvars._ttorsions: xs = [xcc[3 * at:3 * at + 3] for at in inpvars._tatoms[X]] phis.append(np.rad2deg(fncs.dihedral(*xs))) return TorPESpoint(phis)