def accGeneric(donor, donorHyds, acceptor, r2, minAngle):
	if base.verbose:
		print "generic acceptor"
	dp = donor.xformCoord()
	ap = acceptor.xformCoord()
	if donor.element.name == "S":
		r2 = sulphurCompensate(r2)
	if base.verbose:
		print "distance: %g, cut off: %g" % (distance(dp, ap), sqrt(r2))
	if sqdistance(dp, ap) > r2:
		if base.verbose:
			print "dist criteria failed"
		return 0
	if base.verbose:
		print "dist criteria okay"
	 
	ap = acceptor.xformCoord()
	dp = donor.xformCoord()
	for bonded in acceptor.primaryNeighbors():
		bp = bonded.xformCoord()
		if base.verbose:
			print "angle: %g" % angle(bp, ap, dp)
		ang = angle(bp, ap, dp)
		if ang < minAngle:
			if base.verbose:
				print "angle too sharp (%g < %g)" % (ang,
								minAngle)
			return 0
	if base.verbose:
		print "angle(s) okay (all > %g)" % minAngle
	return 1
def testPhiPsi(dp, donorHyds, ap, bp, phiPlane, r2, phi, theta):
	if base.verbose:
		print "distance: %g, cut off: %g" % (distance(dp, ap), sqrt(r2))
	if sqdistance(dp, ap) > r2:
		if base.verbose:
			print "dist criteria failed"
		return 0
	if base.verbose:
		print "dist criteria OK"

	if not testPhi(dp, ap, bp, phiPlane, phi):
		return 0

	return testTheta(dp, donorHyds, ap, theta)
def accThetaTau(donor, donorHyds, acceptor, upsilonPartner, r2,
						upsilonLow, upsilonHigh, theta):
	if base.verbose:
		print "accThetaTau"
	dp = donor.xformCoord()
	ap = acceptor.xformCoord()

	if donor.element.name == "S":
		r2 = sulphurCompensate(r2)
	if base.verbose:
		print "distance: %g, cut off: %g" % (distance(dp, ap), sqrt(r2))
	if sqdistance(dp, ap) > r2:
		if base.verbose:
			print "dist criteria failed"
		return 0
	if base.verbose:
		print "dist criteria okay"
	
	if upsilonPartner:
		upPos = upsilonPartner.xformCoord()
	else:
		# upsilon measured from "lone pair" (bisector of attached
		# atoms)
		bondedPos = []
		for bonded in acceptor.primaryNeighbors():
			bondedPos.append(bonded.xformCoord())
		lonePairs = bondPositions(ap, tetrahedral, 1.0, bondedPos)
		bisectors = []
		for lp in lonePairs:
			bisectors.append(ap - (lp - ap))
		upPos = bisectors[0]
		for bs in bisectors[1:]:
			if base.verbose:
				print "Testing 'extra' lone pair"
			if testThetaTau(dp, donorHyds, ap, bs,
						upsilonLow, upsilonHigh, theta):
				return 1
	return testThetaTau(dp, donorHyds, ap, upPos,
						upsilonLow, upsilonHigh, theta)
Esempio n. 4
0
def _tryFinish(atom, hbondInfo, finished, aroAmines, prunedBy, processed):
	# do we have enough info to establish all H/LP positions for atom?

	bondingInfo = _typeInfo(atom)
	geom = bondingInfo.geometry

	# from number of donors/acceptors, determine
	# if we can position Hs/lone pairs
	numBonds = _numBonds(atom)
	hydsToPosition = bondingInfo.substituents - numBonds
	openings = geom - numBonds

	donors = []
	acceptors = []
	all = []
	for isAcc, other in hbondInfo[atom]:
		all.append(other)
		if isAcc:
			donors.append(other)
		else:
			acceptors.append(other)
	if len(all) < openings \
	and len(donors) < openings - hydsToPosition \
	and len(acceptors) < hydsToPosition:
		if debug:
			print "not enough info (all/donors/acceptors):", len(all), len(donors), len(acceptors)
		return False

	# if so, find their positions and
	# record in hbondInfo; mark as finished
	atPos = atom.xformCoord()
	targets = []
	for isAcc, other in hbondInfo[atom][:2]:
		targets.append(_findTarget(atom, atPos, other, not isAcc,
							hbondInfo, finished))

	# for purposes of this intermediate measurement, use hydrogen
	# distances instead of lone pair distances; determine true
	# lone pair positions once hydrogens are found
	bondedPos = []
	testPositions = []
	coplanar = []
	for bonded in atom.primaryNeighbors():
		bondedPos.append(bonded.xformCoord())
		if bonded.element.number == 1:
			testPositions.append(bonded.xformCoord())
		if geom == planar:
			for btb in bonded.primaryNeighbors():
				if btb == atom:
					continue
				coplanar.append(btb.xformCoord())
	toward = targets[0]
	if len(targets) > 1:
		toward2 = targets[1]
	else:
		toward2 = None
	Hlen = bondWithHLength(atom, geom)
	LPlen = vdwRadius(atom)
	if debug:
		print atom.oslIdent(), "co-planar:", coplanar
		print atom.oslIdent(), "toward:", toward
		print atom.oslIdent(), "toward2:", toward2
	normals = bondPositions(atPos, geom, 1.0, bondedPos,
			coPlanar=coplanar, toward=toward, toward2=toward2)
	if debug:
		print atom.oslIdent(), "bondPositions:", [str(x) for x in normals]
	# use vectors so we can switch between lone-pair length and H-length
	for normal in normals:
		testPositions.append(normal - atPos)

	# try to hook up positions with acceptors/donors
	if atom in aroAmines:
		if debug:
			print "delay finishing aromatic amine"
		return False
	all = {}
	protons = {}
	lonePairs = {}
	conflicting = []
	for isAcc, other in hbondInfo[atom]:
		if debug:
			print "other:", other.oslIdent()
		nearest = None
		if other in finished:
			oprotons, olps = hbondInfo[other]
			if isAcc:
				opositions = oprotons
				mul = LPlen
			else:
				opositions = olps
				mul = Hlen
			for opos in opositions:
				for check in testPositions:
					if isinstance(check, chimera.Vector):
						pos = atPos + check * mul
					else:
						pos = check
					dsq = (opos - pos).sqlength()
					if nearest is None or dsq < nsq:
						nearest = check
						nsq = dsq
		else:
			otherPos = other.xformCoord()
			if isAcc:
				mul = LPlen
			else:
				mul = Hlen
			for check in testPositions:
				if isinstance(check, chimera.Vector):
					pos = atPos + check * mul
				else:
					pos = check
				dsq = (pos - otherPos).sqlength()
				if debug:
					print "dist from other to",
					if isinstance(check, chimera.Point):
						print "pre-existing proton:",
					elif check in all:
						if check in protons:
							print "new proton:",
						else:
							print "new lone pair:",
					else:
						print "unfilled position:",
					import math
					print math.sqrt(dsq)
				if nearest is None or dsq < nsq:
					nearest = check
					nsq = dsq
		if isinstance(nearest, chimera.Point):
			# closest to known hydrogen; no help in positioning...
			if isAcc:
				# other is trying to donate and is nearest
				# to one of our hydrogens
				conflicting.append((isAcc, other))
			continue
		if nearest in all:
			if isAcc:
				if nearest in protons:
					conflicting.append((isAcc, other))
			elif nearest in lonePairs:
				conflicting.append((isAcc, other))
			continue
		# check for steric conflict (frequent with metal coordination)
		if isAcc:
			pos = atPos + nearest * LPlen
			atBump = 0.0
		else:
			pos = atPos + nearest * Hlen
			atBump = Hrad
		checkDist = 2.19 + atBump
		# since searchTree is a module variable that changes,
		# need to access via the module...
		nearby = AddH.searchTree.searchTree(pos.data(), checkDist)
		stericClash = False
		okay = set([atom, other])
		okay.update(atom.primaryNeighbors())
		for nb in nearby:
			if nb in okay:
				continue
			if nb.molecule != atom.molecule \
			and nb.molecule.id == atom.molecule.id:
				# ignore clashes with sibling submodels
				continue
			dChk = vdwRadius(nb) + atBump - 0.4
			if dChk*dChk >= sqdistance(nb.xformCoord(), pos):
				stericClash = True
				if debug:
					print "steric clash with", nb.oslIdent(), "(%.3f < %.3f)" % (pos.distance(nb.xformCoord()), dChk)
				break
		if stericClash:
			conflicting.append((isAcc, other))
			continue

		all[nearest] = 1
		if isAcc:
			if debug:
				print "determined lone pair"
			lonePairs[nearest] = 1
		else:
			if debug:
				print "determined proton"
			protons[nearest] = 1

	for isAcc, other in conflicting:
		if debug:
			print "Removing hbond to %s due to conflict" % other.oslIdent()
		hbondInfo[atom].remove((isAcc, other))
		if not hbondInfo[atom]:
			del hbondInfo[atom]
		if other in finished:
			continue
		try:
			hbondInfo[other].remove((not isAcc, atom))
			if not hbondInfo[other]:
				del hbondInfo[other]
		except ValueError:
			pass
	# since any conflicting hbonds may have been used to determine
	# positions, determine the positions again with the remaining
	# hbonds
	if conflicting:
		# restore hbonds pruned by the conflicting hbonds
		for isAcc, other in conflicting:
			if isAcc:
				key = (other, atom)
			else:
				key = (atom, other)
			for phb in prunedBy.get(key, []):
				if debug:
					print "restoring %s/%s hbond pruned by hbond to %s" % (phb[0].oslIdent(), phb[1].oslIdent(), other.oslIdent())
				processed.remove(phb)
		if atom not in hbondInfo:
			if debug:
				print "No non-conflicting hbonds left!"
			return False
		if debug:
			print "calling _tryFinish with non-conflicting hbonds"
		return _tryFinish(atom, hbondInfo, finished, aroAmines,
							prunedBy, processed)
	# did we determine enough positions?
	if len(all) < openings \
	and len(protons) < hydsToPosition \
	and len(lonePairs) < openings - hydsToPosition:
		if debug:
			print "not enough hookups (all/protons/lps):", len(all), len(protons), len(lonePairs)
		return False

	if len(protons) < hydsToPosition:
		for pos in testPositions:
			if isinstance(pos, chimera.Point):
				continue
			if pos not in all:
				protons[pos] = 1
	Hlocs = []
	for Hvec in protons.keys():
		Hlocs.append(atPos + Hvec * Hlen)

	LPlocs = []
	for vec in testPositions:
		if isinstance(vec, chimera.Point):
			continue
		if vec not in protons:
			LPlocs.append(atPos + vec * LPlen)

	hbondInfo[atom] = (Hlocs, LPlocs)
	finished[atom] = True
	return True
def donWater(donor, donorHyds, acceptor,
					sp2Orp2, sp2Or2, sp2Otheta,
					sp3Orp2, sp3Or2, sp3Otheta, sp3Ophi,
					sp3Nrp2, sp3Nr2, sp3Ntheta, sp3Nupsilon,
					genRp2, genR2, genTheta):
	if base.verbose:
		print "donWater"
	if len(donorHyds) > 0:
		# hydrogens explicitly present,
		# can immediately call donThetaTau
		return donThetaTau(donor, donorHyds, acceptor, sp2Orp2,
			sp2Otheta, sp3Orp2, sp3Otheta, sp3Ophi, sp3Nrp2,
			sp3Ntheta, sp3Nupsilon, genRp2, genTheta)

	ap = acceptor.xformCoord()
	dp = donor.xformCoord()

	accType = acceptor.idatmType
	if not typeInfo.has_key(accType):
		if base.verbose:
			print "Unknown acceptor type failure"
		return 0
	
	geom = typeInfo[accType].geometry
	element = acceptor.element.name
	if element == 'O' and geom == planar:
		if base.verbose:
			print "planar O"
		sq = sqdistance(dp, ap)
		if sq > sp2Or2:
			if base.verbose:
				print "dist criteria failed (%g > %g)" % (
						sqrt(sq), sqrt(sp2Or2))
			return 0
	elif element == 'O' and geom == tetrahedral \
	or element == 'N' and geom == planar:
		if base.verbose:
			print "planar N or tet O"
		sq = sqdistance(dp, ap)
		if sq > sp3Or2:
			if base.verbose:
				print "dist criteria failed (%g > %g)" % (
						sqrt(sq), sqrt(sp3Or2))
			return 0
	elif element == 'N' and geom == tetrahedral:
		if base.verbose:
			print "tet N"
		sq = sqdistance(dp, ap)
		if sq > sp3Nr2:
			if base.verbose:
				print "dist criteria failed (%g > %g)" % (
						sqrt(sq), sqrt(sp3Nr2))
			return 0
	else:
		if base.verbose:
			print "generic acceptor"
		sq = sqdistance(dp, ap)
		if sq > genR2:
			if base.verbose:
				print "dist criteria failed (%g > %g)" % (
						sqrt(sq), sqrt(genR2))
			return 0
	if base.verbose:
		print "dist criteria OK"

	return donThetaTau(donor, donorHyds, acceptor, sp2Orp2,
		sp2Otheta, sp3Orp2, sp3Otheta, sp3Ophi, sp3Nrp2,
		sp3Ntheta, sp3Nupsilon, genRp2, genTheta, isWater=1)
def donGeneric(donor, donorHyds, acceptor, sp2Orp2, sp3Orp2, sp3Nrp2,
	sp2Or2, sp3Or2, sp3Nr2, genRp2, genR2, minHydAngle, minBondedAngle):
	if base.verbose:
		print "donGeneric"
	dc = donor.xformCoord()
	ac = acceptor.xformCoord()

	accType = acceptor.idatmType
	if not typeInfo.has_key(accType):
		return 0

	geom = typeInfo[accType].geometry
	element = acceptor.element.name
	if element == 'O' and geom == planar:
		if base.verbose:
			print "planar O"
		r2 = sp2Or2
		rp2 = sp2Orp2
	elif element == 'O' and geom == tetrahedral \
	or element == 'N' and geom == planar:
		if base.verbose:
			print "planar N or tet O"
		r2 = sp3Or2
		rp2 = sp3Orp2
	elif element == 'N' and geom == tetrahedral:
		if base.verbose:
			print "tet N"
		r2 = sp3Nr2
		rp2 = sp3Nrp2
	else:
		if base.verbose:
			print "generic acceptor"
		if acceptor.element.name == "S":
			r2 = sulphurCompensate(genR2)
			minBondedAngle = minBondedAngle - 9
		r2 = genR2
		rp2 = genRp2

	ap = acceptor.xformCoord()
	dp = donor.xformCoord()
	if len(donorHyds) == 0:
		D2 = dc.sqdistance(ac)
		if D2 > r2:
			if base.verbose:
				print "dist criteria failed (%g > %g)" % (
							sqrt(D2), sqrt(r2))
			return 0
	else:
		for hydPos in donorHyds:
			if sqdistance(hydPos, ap) < rp2:
				break
		else:
			if base.verbose:
				print "hyd dist criteria failed (all >= %g)" % (
								sqrt(rp2))
			return 0
		
	if base.verbose:
		print "dist criteria OK"

	for bonded in donor.primaryNeighbors():
		if bonded.element.number <= 1:
			continue
		bp = bonded.xformCoord()
		ang = angle(bp, dp, ap)
		if ang < minBondedAngle:
			if base.verbose:
				print "bonded angle too sharp (%g < %g)" % (
						ang, minBondedAngle)
			return 0
		
	if len(donorHyds) == 0:
		if base.verbose:
			print "No specific hydrogen positions; default accept"
		return 1

	for hydPos in donorHyds:
		ang = angle(dp, hydPos, ap)
		if ang >= minHydAngle:
			if base.verbose:
				print "hydrogen angle okay (%g >= %g)" % (
						ang, minHydAngle)
			return 1
	if base.verbose:
		print "hydrogen angle(s) too sharp (< %g)" % minHydAngle
	return 0
def donThetaTau(donor, donorHyds, acceptor,
					sp2Orp2, sp2Otheta,
					sp3Orp2, sp3Otheta, sp3Ophi,
					sp3Nrp2, sp3Ntheta, sp3Nupsilon,
					genRp2, genTheta,
					isWater=0):
					# 'isWater' only for hydrogenless water
	if base.verbose:
		print "donThetaTau"
	if len(donorHyds) == 0 and not isWater:
		if base.verbose:
			print "No hydrogens; default failure"
		return 0
	ap = acceptor.xformCoord()
	dp = donor.xformCoord()

	accType = acceptor.idatmType
	if not typeInfo.has_key(accType):
		if base.verbose:
			print "Unknown acceptor type failure"
		return 0
	
	geom = typeInfo[accType].geometry
	element = acceptor.element.name
	if element == 'O' and geom == planar:
		if base.verbose:
			print "planar O"
		for hydPos in donorHyds:
			if sqdistance(hydPos, ap) <= sp2Orp2:
				break
		else:
			if not isWater:
				if base.verbose:
					print "dist criteria failed (all > %g)"\
						% sqrt(sp2Orp2)
				return 0
		theta = sp2Otheta
	elif element == 'O' and geom == tetrahedral \
	or element == 'N' and geom == planar:
		if base.verbose:
			print "planar N or tet O"
		for hydPos in donorHyds:
			if sqdistance(hydPos, ap) <= sp3Orp2:
				break
		else:
			if not isWater:
				if base.verbose:
					print "dist criteria failed (all > %g)"\
						% sqrt(sp3Orp2)
				return 0
		theta = sp3Otheta
		
		# only test phi for acceptors with two bonded atoms
		if len(acceptor.primaryBonds()) == 2:
			if base.verbose:
				print "testing donor phi"
			bonded = acceptor.primaryNeighbors()
			phiPlane, basePos = getPhiPlaneParams(acceptor,
							bonded[0], bonded[1])
			if not testPhi(donor.xformCoord(), ap, basePos,
							phiPlane, sp3Ophi):
				return 0

	elif element == 'N' and geom == tetrahedral:
		if base.verbose:
			print "tet N"
		for hydPos in donorHyds:
			if sqdistance(hydPos, ap) <= sp3Nrp2:
				break
		else:
			if not isWater:
				if base.verbose:
					print "dist criteria failed (all > %g)"\
						% sqrt(sp3Nrp2)
				return 0
		theta = sp3Ntheta

		# test upsilon against lone pair directions
		bondedPos = []
		for bonded in acceptor.primaryNeighbors():
			bondedPos.append(bonded.xformCoord())
		lpPos = bondPositions(ap, geom, 1.0, bondedPos)
		if lpPos:
			# fixed lone pair positions
			for lp in bondPositions(ap, geom, 1.0, bondedPos):
				# invert position so that we are
				# measuring angles correctly
				ang = angle(dp, ap, ap - (lp - ap))
				if ang > sp3Nupsilon:
					if base.verbose:
						print "acceptor upsilon okay"\
							" (%g > %g)" % (
							ang, sp3Nupsilon)
					break
			else:
				if base.verbose:
					print "all acceptor upsilons failed"\
						" (< %g)" % sp3Nupsilon
				return 0
		# else: indefinite lone pair positions; default okay
	else:
		if base.verbose:
			print "generic acceptor"
		if acceptor.element.name == "S":
			genRp2 = sulphurCompensate(genRp2)
		for hydPos in donorHyds:
			if sqdistance(hydPos, ap) <= genRp2:
				break
		else:
			if base.verbose:
				print "dist criteria failed (all > %g)" % sqrt(
								genRp2)
			return 0
		theta = genTheta
	if base.verbose:
		print "dist criteria OK"

	return testTheta(dp, donorHyds, ap, theta)