User:Remig/plico/tug
< User:Remig | plico
Jump to navigation
Jump to search
Tug allows the user to pull or push by mouse actions to move or rotate one part of a polypeptide against the rest by rotation on its psi and phi bonds with collision detection and restriction.
Tug is a member of the Plico suite of protein folding tools described in User:Remig/plico . It may be installed and accessed as a macro with the file:
Title=PLICO Tug Script=script <path to your scripts folder>/tug.spt;plicotug
saved as plicotug.macro in your .jmol/macros folder as described in Macro.
Copy and paste the following into a text editor and save in your scripts folder as tug.spt.
# tug - Jmol script by Ron Mignery # v1.0 beta 2/4/2014 for Jmol 13.4 # # These functions support protein manipulation in Jmol var kTug = 1 var kDtolerance = 0.2 var kAtolerance = 5.0 var kCtolerance = 1.85 var kMtolerance = 0.8 var kMinRama = 2 var kCollisionLimit = 200 var gCanchorIdx = -1 var gCanchorNo = -1 var gNanchorIdx = -1 var gNanchorNo = -1 var gNanchorPidx = -1 var gCanchorXyz = {0 0 0} var gNanchorXyz = {0 0 0} var gNanchorPxyz = {0 0 0} var gCcargoIdx = -1 var gNcargoIdx = -1 var gCcargoXyz = {0 0 0} var gNcargoXyz = {0 0 0} var gCcargoNo = -1 var gNcargoNo = -1 var gDestAtomIdx = -1 var g1pivotIdx = -1 var g2pivotIdx = -1 var gSelSaves = ({}) var gCrotors = array() var gNrotors = array() var gMouseX = 0 var gMouseY = 0 var gAc = ({}) var gChain = "" var gMinNo = 1 var gMaxNo = 9999 var gScheme = "Jmol" var gAltScheme = "Rasmol" var gCargoAtoms = ({}) var gSeed = 23423.52 var gBusy = FALSE var gSCidx = -1 var gSCcircle = -1 var gSCpt = {0 0 0} var gOK = TRUE # global return value to work around jmol *feature* var gOk2 = TRUE # " " var gTargetPt = {0 0 0} var gNewDrag = FALSE var gEcho = "" var gCountdown = 0 var gZoom = "" var gRotate = "" # Return L tetrahedron point if i1<i2<i3, else R point function getTet(i1, i2, i3, dist) { var v1 = {atomIndex=i3}.xyz - {atomIndex=i2}.xyz var v2 = {atomIndex=i1}.xyz - {atomIndex=i2}.xyz var axis = cross(v1, v2) var pma = ({atomIndex=i1}.xyz + {atomIndex=i3}.xyz)/2 var pmo = {atomIndex=i2}.xyz + {atomIndex=i2}.xyz - pma var pt = pmo + (axis/axis) var v = pt - {atomIndex=i2}.xyz var cdist = distance(pt, {atomIndex=i2}) var factor = (dist/cdist) var lpt = v * factor return lpt + {atomIndex=i2}.xyz } function getTrigonal(i1, i2, i3, dist) { var v1 = {atomIndex=i1}.xyz - {atomIndex=i2}.xyz var v2 = {atomIndex=i3}.xyz - {atomIndex=i2}.xyz var pt = {atomIndex=i2}.xyz - (v1 + v2) var v = pt - {atomIndex=i2}.xyz var cdist = distance(pt, {atomIndex=i2}) var factor = (dist/cdist) var lpt = (v * factor) return lpt + {atomIndex=i2}.xyz } function abs( x) { if (x < 0) { x = -x } return x } function getCAmNo (iNo) { while ((iNo > 0) and ({(atomno=iNo) and (chain=gChain)}.atomName != "CA")) { iNo-- } return iNo } function getCAmIdx (idx) { var no = {atomIndex=idx and (chain=gChain)}.atomno no = getCAmNo( no) return ({(atomno=no) and (chain=gChain)}.atomIndex) } function getCApNo (iNo) { while ((iNo < gMaxNo) and ({(atomno=iNo) and (chain=gChain)}.atomName != "CA")) { iNo++ } return iNo } function getCpIdx (idx) { var no = {atomIndex=idx and (chain=gChain)}.atomno no = getCpNo( no) return ({(atomno=no) and (chain=gChain)}.atomIndex) } function getCpNo (iNo) { while ((iNo < gMaxNo) and ({(atomno=iNo) and (chain=gChain)}.atomName != "C")) { iNo++ } return iNo } function getCApIdx (idx) { var no = {atomIndex=idx and (chain=gChain)}.atomno no = getCApNo( no) return ({(atomno=no) and (chain=gChain)}.atomIndex) } function getCmNo (iNo) { while ((iNo > 0) and ({(atomno=iNo) and (chain=gChain)}.atomName != "C")) { iNo-- } return iNo } function getCmIdx (idx) { var no = {atomIndex=idx and (chain=gChain)}.atomno no = getCmNo( no) return ({(atomno=no) and (chain=gChain)}.atomIndex) } function getNmNo (iNo) { while ((iNo > 0) and ({(atomno=iNo) and (chain=gChain)}.atomName != "N")) { iNo-- } return iNo } function getNmIdx (idx) { var no = {atomIndex=idx and (chain=gChain)}.atomno no = getNmNo( no) return ({(atomno=no) and (chain=gChain)}.atomIndex) } function getNpNo (iNo) { while ((iNo < gMaxNo) and ({(atomno=iNo) and (chain=gChain)}.atomName != "N")) { iNo++ } return iNo } function getNpIdx (idx) { var no = {atomIndex=idx}.atomno no = getNpNo( no) return ({(atomno=no) and (chain=gChain)}.atomIndex) } function getCBidx (BBidx) { var no = {atomIndex=BBidx}.atomno var i = 1 for (; i < 5; i++) { if ({(atomno=@{no+i}) and (chain=gChain)}.atomName == "CB") { break } } return {(atomno=@{no+i}) and (chain=gChain)}.atomIndex } function getOidx (BBidx) { var no = {atomIndex=BBidx}.atomno var i = 1 for (; i < 4; i++) { if ({(atomno=@{no+i}) and (chain=gChain)}.atomName == "O") { break } } return {(atomno=@{no+i}) and (chain=gChain)}.atomIndex } function getNwardBBno (iNo) { while ((iNo >= 0) and ( ({(atomno=iNo) and (chain=gChain)}.atomName != "N") and ({(atomno=iNo) and (chain=gChain)}.atomName != "C") and ({(atomno=iNo) and (chain=gChain)}.atomName != "CA"))) { iNo-- } return iNo } function getNwardBBidx (idx) { var no = {atomIndex=idx}.atomno - 1 no = getNwardBBno( no) return ((no >= 0) ? ({(atomno=no) and (chain=gChain)}.atomIndex) : -1) } function getCwardBBno (iNo) { while ((iNo < gMaxNo) and ( ({(atomno=iNo) and (chain=gChain)}.atomName != "N") and ({(atomno=iNo) and (chain=gChain)}.atomName != "C") and ({(atomno=iNo) and (chain=gChain)}.atomName != "CA"))) { iNo++ } return iNo } function getCwardBBidx (idx) { var no = {atomIndex=idx}.atomno + 1 no = getCwardBBno( no) return ((no >= 0) ? ({(atomno=no) and (chain=gChain)}.atomIndex) : -1) } function getScBBidx (idx) { var no = {atomIndex=idx}.atomno for (; no > 0; no--) { if ({(atomno=no) and (chain=gChain)}.atomName == "CA") { break } else if ({(atomno=no) and (chain=gChain)}.atomName == "C") { break } else if ({(atomno=no) and (chain=gChain)}.atomName == "N") { break } else if ({(atomno=no) and (chain=gChain)}.atomName == "CB") { no -= 3 break } } return {(atomno=no) and (chain=gChain)}.atomIndex } function isBBidx(aIdx) { var ret = FALSE switch({atomIndex=aIdx}.atomName) { case "N": case "CA": case "C": ret = TRUE break } return ret } function isSCidx(aIdx) { var ret = FALSE if (isBBidx(aIDx) == FALSE) { ret = TRUE switch({atomIndex=aIdx}.atomName) { case "O": case "CB": ret = FALSE break } } return ret } function addSideChainToSelection(CAno, isAdd, addOXT) { var iNo = CAno+3 while ({(atomno=iNo) and (chain=gChain)}.resno == {(atomno=CAno) and (chain=gChain)}.resno) { {(atomno=iNo) and (chain=gChain)}.selected = isAdd if ({(atomno=iNo) and (chain=gChain)}.atomName == "OXT") { {(atomno=iNo) and (chain=gChain)}.selected = addOXT } iNo++ } } function selectAddSideChain(fromIdx) { var iNo = {atomIndex=fromIdx}.atomno select none while ({(atomno=iNo) and (chain=gChain)}.atomName != "N") { {(atomno=iNo) and (chain=gChain)}.selected = TRUE iNo++ if (iNo > gMaxNo) { break } } } # First and last are BB atoms # Any side atoms in the range are also selected function selectNward (firstIdx, lastIdx) { var firstno = ((firstIdx < 0) ? {atomIndex=lastIdx}.atomno : {atomIndex=firstIdx}.atomno) var lastno = ((lastIdx < 0) ? firstno : {atomIndex=lastIdx}.atomno) select (atomno <= firstno) and (atomno >= lastno) if ({(atomno=firstno) and (chain=gChain)}.atomName == "C") { # if psi addSideChainToSelection(firstno-1, TRUE, TRUE) {(atomno=@{firstno+1}) and (chain=gChain)}.selected = TRUE # add O } if ({(atomno=firstno) and (chain=gChain)}.atomName == "CA") { addSideChainToSelection(firstno, TRUE, FALSE) } if ({(atomno=lastno) and (chain=gChain)}.atomName == "C") { # if psi addSideChainToSelection(lastno-1, FALSE, FALSE) } } # First and last are BB atoms # Any side atoms in the range are also selected function selectCward (firstIdx, lastIdx) { var firstno = ((firstIdx < 0) ? gMaxNo : {atomIndex=firstIdx}.atomno) var lastno = ((lastIdx < 0) ? 1 : {atomIndex=lastIdx}.atomno) # If nWard anchor in range, begin selection with it if (gNanchorIdx >= 0) { var aNo = {atomIndex=gNanchorIdx}.atomno if (aNo > firstNo) { firstno = aNo } } # If cWard anchor in range, end selection with it if (gCanchorIdx >= 0) { var aNo = {atomIndex=gCanchorIdx}.atomno if (aNo < lastNo) { lastno = aNo } } select (atomno >= firstno) and (atomno <= lastno) if ({(atomno=firstno) and (chain=gChain)}.atomName == "C") { # if psi addSideChainToSelection(firstno-1, FALSE, FALSE) } if ({(atomno=lastno) and (chain=gChain)}.atomName == "CA") { addSideChainToSelection(lastno, TRUE, FALSE) } if ({(atomno=lastno) and (chain=gChain)}.atomName == "C") { # if psi addSideChainToSelection(lastno-1, TRUE, TRUE) {(atomno=@{lastno+1}) and (chain=gChain)}.selected = TRUE # add O } } # Selected must include second parameter but not the first function setDistanceIdx (staticIdx, mobileIdx, desired) { try { var v = {atomIndex=mobileIdx}.xyz - {atomIndex=staticIdx}.xyz var dist = distance({atomIndex=staticIdx}, {atomIndex=mobileIdx}) translateSelected @{((v * (desired/dist)) - v)} } catch { } } # Selected must include third parameter but not the first function setAngleIdx (statorIdx, pivotIdx, rotorIdx, toangle) { try { var v1={atomIndex=statorIdx}.xyz - {atomIndex=pivotIdx}.xyz var v2={atomIndex=rotorIdx}.xyz - {atomIndex=pivotIdx}.xyz var axis = cross(v1, v2) + {atomIndex=pivotIdx}.xyz var curangle = angle({atomIndex=statorIdx}, {atomIndex=pivotIdx}, {atomIndex=rotorIdx}) rotateselected @axis {atomIndex = pivotIdx} @{curangle-toangle} } catch { } } # Selected must include fourth parameter but not the first function setDihedralIdx (stator1idx, stator2idx, rotor1idx, rotor2idx, toangle) { try { var a1={atomIndex = stator1idx}.xyz var a2={atomIndex = stator2idx}.xyz var a3={atomIndex = rotor1idx}.xyz var a4={atomIndex = rotor2idx}.xyz var curangle = angle(a1, a2, a3, a4) rotateselected {a3} {a2} @{curangle-toangle} } catch { } } function countCollisions(rc) { var lcAtoms = ({}) for (var idx = {*}.min.atomIndex; idx <= {*}.max.atomIndex; idx++) { lcAtoms = lcAtoms or (within(kCtolerance, FALSE, {atomIndex=idx}) and {atomIndex > idx} and not {rc} and not connected({atomIndex=idx})) } return lcAtoms.size } # Resolve collisions function handleCollisions( nWard, targetIdx) { # For all selected atoms for (var iNo = {selected}.min.atomno; iNo <= {selected}.max.atomno; iNo++) { var idx = {(atomno=iNo) and (chain=gchain)}.atomIndex if ({atomindex=idx}.selected) { # Collect local colliders var lcAtoms = (within(kCtolerance, FALSE, {atomIndex=idx}) and not {atomIndex=idx} and not {gOkCollide} and not connected({atomIndex=idx})) if (lcAtoms.size > 0) { # Ignore kinked BB if (isBBidx(idx) and angle({atomIndex=@{getCwardBBidx(idx)}}, {atomIndex=idx} , {atomIndex=@{getNwardBBidx(idx)}}) < 100) { continue } #gCountdown-- if (gCountdown < 0) { timedOut("Too many collsions") } # For all local water colliders, delete var recollect = FALSE for (var c = 1; c <= lcAtoms.size; c++ ) { if (lcAtoms[c].group = "HOH") { delete {atomIndex=@{lcAtoms[c].atomIndex}} recollect = TRUE } } # Recollect local colliders if needed if (recollect) { lcAtoms = (within(kCtolerance, FALSE, {atomIndex=idx}) and not {atomIndex=idx} and not {gOkCollide} and not connected({atomIndex=idx})) recollect = FALSE } # For all local colliders for (var c = 1; c <= lcAtoms.size; c++ ) { # If it is with side chain not proline, fix it var cidx = lcAtoms[c].atomIndex if (isSCidx(cidx) and ({atomIndex=cidx}.group != "PRO")) { fixSCcollision2(cidx) recollect = TRUE # If not fixed, exit fail if (gOk2 == FALSE) { return # early exit (break n jmol bug) } } } # Recollect local colliders if needed if (recollect) { lcAtoms = (within(kCtolerance, FALSE, {atomIndex=idx}) and not {atomIndex=idx} and not {gOkCollide} and not connected({atomIndex=idx})) } # For all local colliders for (var c = 1; c <= lcAtoms.size; c++ ) { # If it is with O, counter-rotate if ({atomIndex=@{lcAtoms[c].atomIndex}}.atomName = "O") { counterRotate2(idx, lcAtoms[c].atomIndex, targetIdx) # If not fixed, exit fail if (gOk2 == FALSE) { return # early exit (break n jmol bug) } } } } } } # endfor iNo } # Rotate rotor set to move target atom to its proper place function tugTrackIdx(targetIdx, targetPt, nWard, cDetect) { gOK = FALSE var pt = targetPt var dist = distance(pt, {atomIndex=targetIdx}.xyz) var rotors = (nWard ? gNrotors : gCrotors) # For a number of passes for (var pass1 = 0; pass1 < 20; pass1++) { var blocked = ({}) for (var pass2 = 0; pass2 < (rotors.size/4); pass2++) { var v1 = {atomIndex=targetIdx}.xyz - pt # Find the most orthgonal unused rotor var imax = 0 var smax = 0.5 for (var i = 1; i < rotors.size; i += 4) { var i2 = rotors[i+1] var i3 = rotors[i+2] var i4 = rotors[i+3] if ((i2 != targetIdx) and (i3 != targetIdx) and (i4 != targetIdx)) { if ({blocked and {atomIndex=i2}}.count == 0) { var v2 = {atomIndex=i3}.xyz - {atomIndex=i2}.xyz var s = sin(abs(angle(v1, {0 0 0}, v2))) if (s > smax) { smax = s imax = i } } } } # If no more rotors, break to next full try if (imax == 0) { break } var i1 = rotors[imax+0] var i2 = rotors[imax+1] var i3 = rotors[imax+2] var i4 = rotors[imax+3] # Get dihedral of rotor with target point var dt = angle({atomIndex=targetIdx}, {atomIndex=i2}, {atomIndex=i3}, pt) var dh = angle({atomIndex=i1}, {atomIndex=i2}, {atomIndex=i3}, {atomIndex=i4}) if (dh == "NaN") { dh = -50 } var psi = dh + dt var phi = dh + dt # Compute resultant psi and phi # and select from target atom to first half of rotor var movePt = FALSE if (nWard) { if ({atomIndex=i2}.atomName="CA") { psi = angle({atomIndex=@{getCwardBBidx(i1)}}, {atomIndex=i1}, {atomIndex=i2}, {atomIndex=i3}) + dt } else { phi = angle({atomIndex=i1}, {atomIndex=i2}, {atomIndex=i3}, {atomIndex=@{getNwardBBidx(i3)}}) + dt } if ({atomIndex=i2}.atomno > {atomIndex=targetIdx}.atomno) { movePt = TRUE selectNward(i3, getCwardBBidx(targetIdx)) {atomIndex=targetIdx}.selected = TRUE } else { selectCward(i2, targetIdx) } } else { if (({atomIndex=i2}.atomName="CA")) { phi = angle({atomIndex=@{getNwardBBidx(i1)}}, {atomIndex=i1}, {atomIndex=i2}, {atomIndex=i3}) + dt } else { psi = angle({atomIndex=i2}, {atomIndex=i3}, {atomIndex=i4}, {atomIndex=@{getCwardBBidx(i4)}}) + dt } if ({atomIndex=i2}.atomno < {atomIndex=targetIdx}.atomno) { movePt = TRUE selectCward(i3, getNwardBBidx(targetIdx)) {atomIndex=targetIdx}.selected = TRUE } else { selectNward(i2, targetIdx) } } # If rotation within ramachandran limits #var ridx = 1 + (36*(((-psi\10)%180)+18)+(((phi\10)%180)+18)) if ((abs(dt) >= 0.1) and (({atomIndex=i2}.group=="GLY") or (phi < 0))) {#kRama[ridx] >= kMinRama))) { # If moving target point, put the target atom there var cp = {atomIndex=targetIdx}.xyz if (movePt) { dt = -dt {atomIndex=targetIdx}.xyz = pt } # Rotate to minimize vector ==================== rotateSelected {atomIndex=i2} {atomIndex=i3} @dt # If collision checking if (cDetect) { # If collision, back off by eighths var wasCollision = FALSE for (var ci = 0; ci < 4; ci++) { if (ci < 3) { dt /= 2 } handleCollisions( nWard, targetIdx) if (gOk2==FALSE) { wasCollision = TRUE rotateSelected {atomIndex=i2} {atomIndex=i3} @{-dt} } else if (wasCollision) { if (ci <3) { rotateSelected {atomIndex=i2} {atomIndex=i3} @{dt} } } else { break } if (dt < 0.01) { break } } # endfor } # If moving target point, put the target atom back if (movePt) { pt = {atomIndex=targetIdx}.xyz {atomIndex=targetIdx}.xyz = cp } } # If close enough, stop if (distance(pt, {atomIndex=targetIdx}) < kDtolerance) { gOK = TRUE gTargetPt = pt break } # Block rotor blocked |= {atomIndex=i2} } # endfor num rotors passes if (gOK) { break } } # endfor 10 passes } # Counter rotate bonds on either side of a BB O function docounterRotate2(caPhiIDx, nIdx, cIdx, oIdx, caPsiIdx, dir, nWard) { # Rotate phi {atomIndex=nIdx}.selected = nWard {atomIndex=cIdx}.selected = nWard {atomIndex=oIdx}.selected = nWard rotateSelected {atomIndex=caPsiIdx} {atomIndex=cIdx} @{dir} # Counter-rotate psi {atomIndex=nIdx}.selected = not nWard {atomIndex=cIdx}.selected = not nWard {atomIndex=oIdx}.selected = not nWard rotateSelected {atomIndex=nIdx} {atomIndex=caPhiIdx} @{-dir} } function counterRotate2(aIdx, bIdx, targetIdx) { var selsave = {selected} gOk2 = TRUE var oIdx = aIdx var xIdx = bIdx if ({atomIndex=bIdx}.atomName=="O") { oIdx = bIdx xIdx = aIdx } var cIdx = getScBBidx(oIdx) var nIdx = getCwardBBidx(cIdx) var caPhiIdx = getCwardBBidx(nIdx) var caPsiIdx = getNwardBBidx(cIdx) var nWard = ({atomIndex=oIdx}.atomno < {atomIndex=targetIdx}.atomno) if (nWard) { selectCward(cIdx, targetIdx) } else { selectNward(nIdx, targetIdx) } # Until all collisions cancelled var dir = 5 var ang = angle({atomIndex=xIdx}, {atomIndex=oIdx}, {atomIndex=cIdx}) var tcount = 0 while (within(kCtolerance, FALSE, {atomIndex=oIdx}) and not {atomIndex=oIdx} and not connected({atomIndex=oIdx}) and not {gOkCollide} > 0) { # Counter-rotate docounterRotate2(caPhiIDx, nIdx, cIdx, oIdx, caPsiIdx, dir, nWard) var newang = angle({atomIndex=xIdx}, {atomIndex=oIdx}, {atomIndex=cIdx}) # If wrong direction once, undo and reverse if (newang > ang) { docounterRotate2(caPhiIDx, nIdx, cIdx, oIdx, caPsiIdx, -dir, nWard) # If first time, continue in opposite direction dir *= -1 if (dir < 0) { continue } } # If no go, undo and exit tcount++ if (tcount > (360/abs(dir))) { gOk2 = FALSE break } } # endwhile select selsave } # Repair proline function repairProline(idx) { var cbidx = getCBidx(idx) var cbno = {atomIndex=cbidx}.atomno var cgidx = {(atomno=@{cbno+1}) and (chain=gChain)}.atomIndex var cdidx = {(atomno=@{cbno+2}) and (chain=gChain)}.atomIndex var caidx = {(atomno=@{cbno-3}) and (chain=gChain)}.atomIndex var nidx = {(atomno=@{cbno-4}) and (chain=gChain)}.atomIndex select {atomIndex=cbidx} setAngleIdx(nidx, caidx, cbidx, 109.5) select {atomIndex=cdidx} setDistanceIdx(nidx, cdidx, 1.47) setAngleIdx(caidx, nidx, cdidx, 102.7) setDihedralIdx(cbidx, caidx, nidx, cdidx, 16.2) select {atomIndex=cgidx} setDistanceIdx(cdidx, cgidx, 1.51) setAngleIdx(nidx, cdidx, cgidx, 106.4) setDihedralIdx(caidx, nidx, cdidx, cgidx, 16.2) } # Repair side chain function plicoRepairSideChain(targetIdx, nWard) { var idx = (nWard ? getCwardBBidx(targetIdx) : getNwardBBidx(targetIdx)) if (({atomIndex=targetIdx}.atomName == "CA") and ({atomIndex=targetIdx}.group != "GLY")) { var cbidx = getCBidx(targetIdx) select none selectAddSideChain(cbidx) setAngleIdx(idx, targetIdx, cbidx, 110.0) setDistanceIdx(targetIdx, cbidx, 1.5) if ({atomIndex=targetIdx}.group != "PRO") { var colliders = (within(kCtolerance, FALSE, {selected}) and not {atomIndex=targetIdx} and not {selected}) if (colliders.size > 0) { if ({atomIndex=targetIdx}.group != "ALA") { fixSCcollision2(cbidx) } } } else { if (nWard) { } else { setDihedralIdx(getNwardBBidx(idx), idx, targetIdx, cbidx, 174.2) } } } else if ({atomIndex=targetIdx}.atomName == "C") { var oidx = getOidx(targetIdx) select {atomIndex=oidx} setAngleIdx(idx, targetIdx, oidx, 120.0) setDistanceIdx(targetIdx, oidx, 1.21) if (nWard) { setDihedralIdx(getCwardBBidx(idx), idx, targetIdx, oidx, 0.0) } if ({atomIndex=idx}.group == "PRO") { repairProline(idx) var dNo = {atomIndex=targetIdx}.atomno + 4 var dIdx = {(atomno=dNO) and (chain=gChain)}.atomIndex var colliders = (within(kCtolerance, FALSE, {atomIndex=dIdx}) and not connected({atomIndex=dIdx}) and not {atomIndex=dIdx}) for (var i = 1; i <= colliders.size; i++) { if (colliders[i].atomName == "O") { counterRotate2(dIdx, colliders[i].atomIndex, targetIdx) } } } } } # Rebuild Cward rotors set function tugTrackC() { # For all bb atoms cWard of cargo var targetIdx = gCcargoIdx var okCount = 0 # Allow collisions with cargo gOkCollide = gCargoAtoms var tcount = 0 while (targetIdx != gCanchorIdx) { # Step to next atom targetIdx = getCwardBBidx(targetIdx) # No collision with cargo allowed after two atoms placed if (tcount == 2) { gOkCollide = ({}) } tcount++ # Compute targets desired coords var c1idx = getCwardBBidx(targetIdx) var n1idx = getNwardBBidx(targetIdx) var n2idx = getNwardBBidx(n1Idx) var n3idx = getNwardBBidx(n2Idx) var pt = {0 0 0} if ({atomIndex=targetIdx}.atomName == "N") { var oidx = getOidx(n1idx) select {atomIndex=oidx} # Desired target location is trigonal O setDistanceIdx(n1idx, oidx, 1.5) pt = getTrigonal(n2idx, n1idx, oidx, 1.37) setDistanceIdx(n1idx, oidx, 1.21) } else if (({atomIndex=targetIdx}.atomName == "C") and ({atomIndex=targetIdx}.group != "GLY")) { # Desired target location is tetragonal CB var cbidx = getCBidx(n1idx) pt = getTet(n2idx, n1idx, cbidx, 1.5) } else { # CA (or GLY C) # Save current target coords var cp = {atomIndex=targetIdx}.xyz # Set target atom at desired distance and angle select {atomIndex=targetIdx} setDistanceIdx(n1idx, targetIdx, 1.5) setAngleIdx(n2idx, n1idx, targetIdx, 110.0) if ({atomIndex=targetIdx}.atomName == "CA") { setDihedralIdx(n3idx, n2idx, n1idx, targetIdx, 180) } # Record and restore target pt = {atomIndex=targetIdx}.xyz {atomIndex=targetIdx}.xyz = cp } # If target not at desired location if (distance(pt, {atomIndex=targetIdx}) > kDtolerance) { okCount = 0 gTargetPt = pt var xcount = 0 gOK = FALSE while ((xcount < 20) and (gOK == FALSE)) { # Rotate on cWard rotor set to move it there tugTrackIdx(targetIdx, pt, FALSE, FALSE) #(distance(pt, {atomIndex=targetIdx}) > kMtolerance)) xcount++ } } else { gOK = TRUE okCount++ } # If successful if (gOK == TRUE) { # Adust any side atoms plicoRepairSideChain(targetIdx, FALSE) } # Else fail else { break } # If no movement in 4 tries, we are done if (okCount > 3) { break } } # endwhile (targetIdx != gCanchorIdx) { } # Rebuild Nward rotors set function tugTrackN() { gOK = TRUE # For all bb atoms nWard of cargo var targetIdx = gNcargoIdx var okCount = 0 # Allow collisions with cargo gOkCollide = gCargoAtoms var tcount = 0 while (targetIdx != gNanchorIdx) { # Step to next atom targetIdx = getNwardBBidx(targetIdx) # No collision with cargo allowed after two atoms placed if (tcount == 2) { gOkCollide = ({}) } tcount++ # Compute targets desired coords var n1idx = getNwardBBidx(targetIdx) var c1idx = getCwardBBidx(targetIdx) var c2idx = getCwardBBidx(c1idx) var c3idx = getCwardBBidx(c2idx) var pt = {0 0 0} if ({atomIndex=targetIdx}.atomName == "CA") { # Desired target location is trigonal O var oidx = getOidx(c1idx) select {atomIndex=oidx} setDistanceIdx(c1idx, oidx, 1.39) pt = getTrigonal(c2idx, c1idx, oidx, 1.41) setDistanceIdx(c1idx, oidx, 1.21) } else if (({atomIndex=targetIdx}.atomName == "N") and ({atomIndex=targetIdx}.group != "GLY")) { # Desired target location is r-tetragonal CB var cbidx = getCBidx(c1idx) pt = getTet(cbidx, c1idx, c2idx, 1.5) } else { # C # Save current target coords var cp = {atomIndex=targetIdx}.xyz # Set target atom at desired distance and angle select {atomIndex=targetIdx} setDistanceIdx(c1idx, targetIdx, 1.37) setAngleIdx(c2idx, c1idx, targetIdx, 110.0) if ({atomIndex=targetIdx}.group == "PRO") { setDihedralIdx(c3idx, c2idx, c1idx, targetIdx, -57.0) } # Record and restore target pt = {atomIndex=targetIdx}.xyz {atomIndex=targetIdx}.xyz = cp } # If target not at desired location if (distance(pt, {atomIndex=targetIdx}) > kDtolerance) { var okCount = 0 gTargetPt = pt var xcount = 0 gOK = FALSE while ((xcount < 20) and (gOK == FALSE)) { # Rotate on cWard rotor set to move it there tugTrackIdx(targetIdx, pt, TRUE, FALSE) #(distance(pt, {atomIndex=targetIdx}) > kMtolerance)) xcount++ } } else { gOK = TRUE okCount++ } # If sucessful if (gOK == TRUE) { # Adust any side atoms plicoRepairSideChain(targetIdx, TRUE) } # Else fail else { break } # If no movement in 4 tries, we are done if (okCount > 3) { break } } # endwhile (targetIdx != gNanchorIdx) { } # gPlicoRecord is maintained by the macro pilcoRecord function plicoRecord(s) { var g = format("show file \"%s\"", gPlicoRecord) var ls = script(g) if (ls.find("FileNotFoundException")) { ls = "" } ls += s write var ls @gPlicoRecord } # gPlicoRecord is maintained by the macro pilcoRecord function translateSelectedRecord(pt) { if (gPlicoRecord != "") { plicoRecord(format("select %s;translateSelected %s;", {selected}, pt)) } translateSelected @pt } # gPlicoRecord is maintained by the macro pilcoRecord function rotateSelectedRecord(g1pivotIdx, axis, a) { if (gPlicoRecord != "") { plicoRecord(format("select %s;", {selected})) plicoRecord(format("rotateSelected {atomIndex=%d} @%s @%s;", g1pivotIdx, axis, a)) } rotateSelected {atomIndex=g1pivotIdx} @axis @a } function collectSCrotors(no) { var scBondIdxs = array() for (var iNo = no; iNo >= 0; iNo--) { var ile = 0 switch ({(atomno=iNo) and (chain=gChain)}.atomName) { case "CA" : return scBondIdxs # Early exit since break 1 appears broken #break 1 case "CZ" : if ({(atomno=iNo) and (chain=gChain)}.group == "TYR") { break } case "CE" : if ({(atomno=iNo) and (chain=gChain)}.group == "MET") { break } case "CG1" : if ({(atomno=iNo) and (chain=gChain)}.group == "VAL") { break } if ({(atomno=iNo) and (chain=gChain)}.group == "ILE") { ile = 1 } case "NE" : case "CD" : case "SD" : case "CG" : case "CB" : scBondIdxs += {(atomno=@{iNo+1+ile}) and (chain=gChain)}.atomIndex scBondIdxs += {(atomno=@{iNo+0}) and (chain=gChain)}.atomIndex if ({(atomno=iNo) and (chain=gChain)}.atomName%2 == "CG") { scBondIdxs += {(atomno=@{iNo-1}) and (chain=gChain)}.atomIndex scBondIdxs += {(atomno=@{iNo-4}) and (chain=gChain)}.atomIndex } else if ({(atomno=iNo) and (chain=gChain)}.atomName == "CB") { scBondIdxs += {(atomno=@{iNo-3}) and (chain=gChain)}.atomIndex scBondIdxs += {(atomno=@{iNo-4}) and (chain=gChain)}.atomIndex } else { scBondIdxs += {(atomno=@{iNo-1}) and (chain=gChain)}.atomIndex scBondIdxs += {(atomno=@{iNo-2}) and (chain=gChain)}.atomIndex } break } } return scBondIdxs } # Drag Side Chain function dragSC() { var iNo = {atomIndex=gSCidx}.atomno if ({atomIndex=gSCidx}.group != "PRO") { var scBondIdxs = collectSCrotors( iNo) var numChi = scBondIdxs.size / 4 var dist = distance({atomIndex=gSCidx}.xyz, gSCpt) # For all rotor combinations var dh = array() for (var i = 0; i < numChi; i++) { dh += angle({atomIndex=@{scBondIdxs[4+(4*i)]}}, {atomIndex=@{scBondIdxs[3+(4*i)]}}, {atomIndex=@{scBondIdxs[2+(4*i)]}}, {atomIndex=@{scBondIdxs[1+(4*i)]}}) } for (var i = 0; i < numChi; i++) { var rot = -120 for (var j = 0; j < 6; j++) { rot += 60*j selectAddSideChain(scBondIdxs[1+(4*i)]) setDihedralIdx(scBondIdxs[4+(4*i)], scBondIdxs[3+(4*i)], scBondIdxs[2+(4*i)], scBondIdxs[1+(4*i)], rot) var newDist = distance({atomIndex=gSCidx}.xyz, gSCpt) # Find the best if (newDist < dist) { dist = newDist for (var k = 0; k < numChi; k++) { dh[k+1] = angle({atomIndex=@{scBondIdxs[4+(4*k)]}}, {atomIndex=@{scBondIdxs[3+(4*k)]}}, {atomIndex=@{scBondIdxs[2+(4*k)]}}, {atomIndex=@{scBondIdxs[1+(4*k)]}}) } } } } # Now set the best for (var i = 0; i < numChi; i++) { selectAddSideChain(scBondIdxs[1+(4*i)]) setDihedralIdx(scBondIdxs[4+(4*i)], scBondIdxs[3+(4*i)], scBondIdxs[2+(4*i)], scBondIdxs[1+(4*i)], dh[i+1]) } } else { # PRO - toggle between puckers up and down var icd = {(atomno=@{iNo+1}) and (chain=gChain)}.atomIndex var icb = {(atomno=@{iNo-1}) and (chain=gChain)}.atomIndex var ica = {(atomno=@{iNo-4}) and (chain=gChain)}.atomIndex var in = {(atomno=@{iNo-5}) and (chain=gChain)}.atomIndex select {atomIndex=gSCidx} if (angle({atomIndex=ica}, {atomIndex=in}, {atomIndex=icd}, {atomIndex=gSCidx}) < -10.0) { setDihedralIdx(ica, in, icd, gSCidx, 8.7) setAngleIdx(in, icd, gSCidx, 110.0) setDistanceIdx(icd, gSCidx, 1.5) } else { setDihedralIdx(ica, in, icd, gSCidx, -29.5) setAngleIdx(in, icd, gSCidx, 108.8) setDistanceIdx(icd, gSCidx, 1.5) } } draw gSCcircle CIRCLE {atomIndex=gSCidx} MESH NOFILL gSCpt = {atomIndex=gSCidx}.xyz } # Fix side chain collisions function fixSCcollision2(idx) { gOk2 = FALSE var iNo = {atomIndex=idx}.atomno var resno = {(atomno=iNo) and (chain=gChain)}.resno # Get SC terminus while (resno == {(atomno=iNo) and (chain=gChain)}.resno) { iNo++ } iNo-- var sc = array() var iBno = iNo while ({(atomno=iBno) and (chain=gChain)}.atomName != "CB") { sc += {(atomno=iBno) and (chain=gChain)} iBno-- } var cbidx = {(atomno=iBno) and (chain=gChain)}.atomIndex var scBondIdxs = collectSCrotors( iNo) var numChi = scBondIdxs.size / 4 # For all rotor combinations for (var i = 0; i < numChi; i++) { var rot = -120 for (var j = 0; j < 6; j++) { rot += 60 selectAddSideChain(scBondIdxs[1+(4*i)]) #setDihedralIdx(scBondIdxs[4+(4*i)], scBondIdxs[3+(4*i)], # scBondIdxs[2+(4*i)], scBondIdxs[1+(4*i)], rot) setDihedralIdx(scBondIdxs[1+(4*i)], scBondIdxs[2+(4*i)], scBondIdxs[3+(4*i)], scBondIdxs[4+(4*i)], rot) # If no collision, exit colliders = (within(kCtolerance, FALSE, {sc}) and not {atomIndex=cbidx} and not {sc}) # If it is with water, delete the water for (var c = 1; c < colliders.size; c++ ) { if (colliders[c].group = "HOH") { delete {atomIndex=@{colliders[c].atomIndex}} colliders = {colliders and not @{colliders[c]}} } } if (colliders.size == 0) { gOk2 = TRUE return # Early exit since break 1 appears broken #break 1 } } } } function isMovableSideChain(aIdx) { var ret = (({atomIndex=aIdx}.group != "PRO") or ({atomIndex=aIdx}.atomName == "CG")) switch({atomIndex=aIdx}.atomName) { case "N": case "CA": case "C": case "CB": case "O": case "O4\'": ret = FALSE break } return ret } # gFreeze is maintained by the script plicoFreeze that allows the user # to inhibit rotation on selected rotors function isRotorAvailable(idx) { return (gFreeze.find(idx) == 0) } function collectBBrotors(nWard) { var anchorNo = (nWard ? ((gNanchorIdx >= 0) ? {atomIndex=gNanchorIdx}.atomno : gMinNo) : ((gCanchorIdx >= 0) ? {atomIndex=gCanchorIdx}.atomno : gMaxNo)) var cargoNo = (nWard ? ((gNcargoIdx >= 0) ? {atomIndex=gNcargoIdx}.atomno : {atomIndex=gCcargoIdx}.atomno) : {atomIndex=gCcargoIdx}.atomno) var rotors = array() if (cargoNo < anchorNo) { # If cWard cargo is C, include its psi if ({(atomno=cargoNo) and (chain=gChain)}.atomName == "C") { #cargoNo-- } for (var iNo = cargoNo; iNo <= anchorNo; iNo++) { if ({(atomno=iNo) and (chain=gChain)}.atomName == "CA") { if (isRotorAvailable(iNo)) { if (({(atomno=iNo) and (chain=gChain)}.group != "PRO") and (iNo > cargoNo)) { # phi rotors += [{(atomno=@{getCmNo(iNo-1)}) and (chain=gChain)}.atomIndex, {(atomno=@{iNo-1}) and (chain=gChain)}.atomIndex] rotors += [{(atomno=@{iNo}) and (chain=gChain)}.atomIndex, {(atomno=@{iNo+1}) and (chain=gChain)}.atomIndex] } if (iNo != (anchorNo-1)) { # psi rotors += [{(atomno=@{iNo-1}) and (chain=gChain)}.atomIndex, {(atomno=@{iNo}) and (chain=gChain)}.atomIndex] rotors += [{(atomno=@{iNo+1}) and (chain=gChain)}.atomIndex, {(atomno=@{getNpNo(iNo+2)}) and (chain=gChain)}.atomIndex] } } } } } else { # If nWard cargo is C, include its phi if ({(atomno=cargoNo) and (chain=gChain)}.atomName == "N") { #cargoNo++ } for (var iNo = cargoNo; iNo >= anchorNo; iNo--) { if ({(atomno=iNo) and (chain=gChain)}.atomName == "CA") { if (isRotorAvailable(iNo)) { if ((iNo != (anchorNo-1)) and (iNo < cargoNo)) { # psi rotors += [{(atomno=@{getNpNo(iNo+2)}) and (chain=gChain)}.atomIndex, {(atomno=@{iNo+1}) and (chain=gChain)}.atomIndex] rotors += [{(atomno=@{iNo}) and (chain=gChain)}.atomIndex, {(atomno=@{iNo-1}) and (chain=gChain)}.atomIndex] } if ({(atomno=iNo) and (chain=gChain)}.group != "PRO") { # phi rotors += [{(atomno=@{iNo+1}) and (chain=gChain)}.atomIndex, {(atomno=@{iNo}) and (chain=gChain)}.atomIndex] rotors += [{(atomno=@{iNo-1}) and (chain=gChain)}.atomIndex, {(atomno=@{getCmNo(iNo-1)}) and (chain=gChain)}.atomIndex] } } } } } if (nWard) { gNrotors = rotors if (FALSE) {#DEBUG print ("gNrotors atomnos")#DEBUG for (var i = 1; i < gNrotors.size; i += 4) {#DEBUG print format("%d %d %s", {atomIndex=@{gNrotors[i]}}.atomno, {atomIndex=@{gNrotors[i+1]}}.atomno, format("%d %d", {atomIndex=@{gNrotors[i+2]}}.atomno, {atomIndex=@{gNrotors[i+3]}}.atomno)) } }#DEBUG } else { gCrotors = rotors if (FALSE) {#DEBUG print ("gCrotors atomnos")#DEBUG for (var i = 1; i < gCrotors.size; i += 4) {#DEBUG print format("%d %d %s", {atomIndex=@{gCrotors[i]}}.atomno, {atomIndex=@{gCrotors[i+1]}}.atomno, format("%d %d", {atomIndex=@{gCrotors[i+2]}}.atomno, {atomIndex=@{gCrotors[i+3]}}.atomno)) } }#DEBUG } } function collectRotors() { collectBBrotors(FALSE) collectBBrotors(TRUE) } function tugSideChain(pt) { # If destination atom defined if (gDestAtomIdx >= 0) { v = {atomIndex=gDestAtomIdx}.xyz - {atomIndex=gSCidx}.xyz if (abs(angle({atomIndex=gDestAtomIdx}.xyz, {0 0 0}, pt)) < 90) { pt = -v/20.0 } else { pt = v/20.0 } } gSCpt += pt draw arrow {atomIndex=gSCidx} @gSCpt } function setColors() { select all color {selected} @gScheme color {atomIndex=gCanchorIdx} @gAltScheme color {atomIndex=gNanchorIdx} @gAltScheme color {atomIndex=g1pivotIdx} green color {atomIndex=g2pivotIdx} green color @gCargoAtoms @gAltScheme select {(atomIndex=gCcargoIdx) or (atomIndex=gNcargoIdx)} halo on select {atomIndex=gDestAtomIdx} star on select none } function clearAtomIdxs() { gCcargoIdx = -1 gNcargoIdx = -1 gCanchorIdx = -1 gNanchorIdx = -1 g1pivotIdx = -1 g2pivotIdx = -1 gDestAtomIdx = -1 gSCidx = -1 } function timedOut (s) { timeout ID"tug" OFF prompt(s) gBusy = FALSE background ECHO yellow restore state gState select gCargoAtoms refresh quit } function recordDrag() { var ls = format("select %s;", {selected}) ls += format("gCanchorIdx = %d;", gCanchorIdx) ls += format("gCanchorNo = %d;", gCanchorNo) ls += format("gNanchorIdx = %d;", gNanchorIdx) ls += format("gNanchorNo = %d;", gNanchorNo) ls += format("gNanchorPidx = %d;", gNanchorPidx) ls += format("gCanchorXyz = %s;", gCanchorXyz) ls += format("gNanchorXyz = %s;", gNanchorXyz) ls += format("gNanchorPxyz = %s;", gNanchorPxyz) ls += format("gCcargoIdx = %d;", gCcargoIdx) ls += format("gNcargoIdx = %d;", gNcargoIdx) ls += format("gCcargoXyz = %s;", gCcargoXyz) ls += format("gNcargoXyz = %s;", gNcargoXyz) ls += format("gCcargoNo = %d;", gCcargoNo) ls += format("gNcargoNo = %d;", gNcargoNo) ls += format("gDestAtomIdx = %d;", gDestAtomIdx) ls += format("g1pivotIdx = %d;", g1pivotIdx) ls += format("g2pivotIdx = %d;", g2pivotIdx) ls += format("gAc = %s;", gAc) ls += format("gChain = \"%s\";", gChain) ls += format("gMinNo = %d;", gMinNo) ls += format("gMaxNo = %d;", gMaxNo) ls += format("gCargoAtoms = %s;", gCargoAtoms) ls += format("gSCidx = %d;", gSCidx) ls += format("gSCcircle = %d;", gSCcircle) ls += format("gSCpt = %s;", gSCpt) ls += "collectRotors();" ls += "tugDragDoneMB();" plicoRecord(ls) } # Bound to LEFT-UP by tugEnableDrag function tugDragDoneMB() { if (gPlicoRecord != "") { recordDrag() } # Move by rotation on rotor sets, smallest first gBusy = TRUE background ECHO pink refresh # If side chain mode if (gSCidx >= 0) { dragSC() } # Else else { gOK = TRUE timeout ID"tug" 20.0 "timedOut(\"Tug timed out\")" gCountdown = kCollisionLimit if ((gCrotors.size < gNrotors.size) or (gNanchorIdx < 0)) { if (gCrotors.size > 4) { tugTrackC() # PULLSTRING MODEL } if (gOK and (gNrotors.size > 4)) { tugTrackN() # PULLSTRING MODEL } } else { if (gNrotors.size > 4) { tugTrackN() # PULLSTRING MODEL } if (gOK and (gCrotors.size > 4)) { tugTrackC() # PULLSTRING MODEL } } timeout ID"tug" OFF # If anchor angles acute, fail if (gOK == TRUE) { if (gCanchorIdx >= 0) { var ic = getCwardBBidx(gCanchorIdx) var in = getNwardBBidx(gCanchorIdx) if ((ic >= 0) and angle({atomIndex=ic}, {atomIndex=gCanchorIdx}, {atomIndex=in}) < 100.0) { gOK = FALSE } } if (gNanchorIdx >= 0) { var ic = getCwardBBidx(gNanchorIdx) var in = getNwardBBidx(gNanchorIdx) if ((in >= 0) and angle({atomIndex=ic}, {atomIndex=gNanchorIdx}, {atomIndex=in}) < 100.0) { gOK = FALSE } } } # If too far if (gOK == FALSE) { timedOut("TUG TOO FAR!") } # Else OK else { select ((atomno >= gNanchorNo) and (atomno <= gCanchorNo) and (chain = gChain)) var idx = {atomno=@{{chain=gChain}.min.atomno}}.atomIndex var i = 0 for (; i < 3; i++) { handleCollisions(FALSE, idx) if (countCollisions() == 0) { break } } if (i == 3) { var p = prompt("Unable to handle all collisions!") restore state gState } } } select {gCargoAtoms} gBusy = FALSE background ECHO yellow refresh } # Bound to ALT-LEFT-DRAG by tugEnableDrag function tugDragMB() { if (gBusy == FALSE) { var dx = (20.0 * (_mouseX - gMouseX))/_width var dy = (20.0 * (_mouseY - gMouseY))/_height var q = quaternion(script("show rotation")) var ptd = {@dx @dy 0} var pt = (!q)%ptd if (distance(pt, {0 0 0}) > 0.004) { # If sidechain mode if (gSCidx >= 0) { tugSideChain(pt) } # Else else { # If new drag if (gNewDrag) { gNewDrag = FALSE save state gState } #mp = ({atomIndex=gNcargoIdx}.xyz + {atomIndex=gCcargoIdx}.xyz )/2.0 # If destination atom defined if (gDestAtomIdx >= 0) { var v = {atomIndex=gDestAtomIdx}.xyz - {selected}.xyz if (abs(angle({atomIndex=gDestAtomIdx}.xyz, {0 0 0}, pt)) < 90) { pt = -v/20.0 } else { pt = v/20.0 } } # Move the cargo select {gCargoAtoms} # If pivots defined, rotate it if (g1pivotIdx >= 0) { # If two pivots var axis = {0 0 0} if (g2pivotIdx >= 0) { axis = {atomIndex=g2pivotIdx} } # Else else { axis = cross(pt, {0 0 0}) + {atomIndex=g1pivotIdx}.xyz } var a = ((abs(angle(pt + {atomIndex=g1pivotIdx}.xyz, {atomIndex=g1pivotIdx}.xyz, axis)) < 90) ? -2 : 2) #rotateSelected {atomIndex=g1pivotIdx} @axis @a rotateSelectedRecord(g1pivotIdx, axis, a) } # Else translate it else { #translateSelected @pt translateSelectedRecord(pt) } # If collisions var aset = {((atomno < gCanchorNo) and (atomno > gNanchorNo) and (chain=gChain))} var ac = (within(kCtolerance, FALSE, {aset}) and not {aset} and not connected(aset)) if (ac.size > 0) { # Resolve them for (var i = 1; i <= ac.size; i++) { select ac[i] handleCollisions() } # If unable if (gOk2 == FALSE) { # Back off background ECHO pink delay 1 if (g1pivotIdx >= 0) { rotateSelectedRecord(g1pivotIdx, axis, -a) } else { translateSelectedRecord(-pt) } background ECHO yellow } } #tugDragDoneMB() } gMouseX = _mouseX gMouseY = _mouseY } select {gCargoAtoms} } } # Bound to ALT-LEFT-DOWN by tugEnableDrag function tugMarkMB() { gMouseX = _mouseX gMouseY = _mouseY gNcargoXyz = {atomIndex=gNcargoIdx}.xyz gCcargoXyz = {atomIndex=gCcargoIdx}.xyz gNewDrag = TRUE } # Called by tugCargoMB and by tugAnchorMB or tugPivotMB when cargo exists function tugEnableDrag() { gEcho = "ALT-CLICK=set cargo range|ALT-DRAG=move|SHIFT=set anchors|ALT-CTRL=set pivots|ALT-SHIFT=set dest atom |DOUBLE-CLICK=exit" echo @gEcho # Allow atoms to be dragged bind "ALT-LEFT-DOWN" "tugMarkMB"; bind "ALT-LEFT-UP" "tugDragDoneMB";#ONCEMODE bind "ALT-LEFT-DRAG" "tugDragMB"; } # Bound to SHIFT-LEFT-CLICK by tugCargoMB function tugAnchorMB() { if ({atomIndex=_atomPicked}.chain == gChain) { var aPidx = getScBBidx( _atomPicked) var pno = {atomIndex=aPidx}.atomno if (pno > {atomIndex=gCcargoIdx}.atomno) { color {atomIndex=gCanchorIdx} @gScheme if (gCanchorIdx == aPidx) { gCanchorIdx = -1 gCanchorNo = gMaxNo + 1 } else { gCanchorIdx = aPidx gCanchorNo = {atomIndex=gCanchorIdx}.atomno gCanchorXyz = {atomIndex=gCanchorIdx}.xyz color {atomIndex=gCanchorIdx} @gAltScheme } collectBBrotors(FALSE) } if (pno < {atomIndex=gNcargoIdx}.atomno) { color {atomIndex=gNanchorIdx} @gScheme if (gNanchorIdx == aPidx) { gNanchorIdx = -1 gNanchorNo = gMinNo - 1 } else { gNanchorIdx = aPidx gNanchorNo = {atomIndex=gNanchorIdx}.atomno gNanchorPidx = getCwardBBidx( aPidx) gNanchorXyz = {atomIndex=gNanchorIdx}.xyz gNanchorPxyz = {atomIndex=gNanchorPidx}.xyz color {atomIndex=gNanchorIdx} @gAltScheme } collectBBrotors(TRUE) } } # Get connectors between fixed and moving part var aset = {((atomno < gCanchorNo) and (atomno > gNanchorNo) and (chain=gChain))} gAc = (within(kCtolerance, FALSE, {aset}) and not {aset}) select {gCargoAtoms} } # Bound to ALT-SHIFT-LEFT-CLICK by tugCargoMB function tugDestAtomMB() { var aOk = TRUE if ({atomIndex=_atomPicked}.chain == gChain) { var pno = {atomIndex=_atomPicked}.atomno if ((pno <= {atomIndex=gCcargoIdx}.atomno) and (pno >= {atomIndex=gNcargoIdx}.atomno)) { aOk = FALSE } } if (aOk) { select {atomIndex=gDestAtomIdx} star off if (gDestAtomIdx == _atomPicked) { gDestAtomIdx = -1 } else { gDestAtomIdx = _atomPicked select {atomIndex=gDestAtomIdx} star on } select {gCargoAtoms} } } # Bound to CTRL-LEFT-CLICK by tugCargoMB function tugPivotMB() { if (g1pivotIdx == _atomPicked) { color {atomIndex=g1pivotIdx} @gScheme if (g2pivotIdx >= 0) { g1pivotIdx = g2pivotIdx g2pivotIdx = -1 } else { g1pivotIdx = -1 } } else if (g2pivotIdx == _atomPicked) { color {atomIndex=g2pivotIdx} @gScheme g2pivotIdx = -1 } else if (g1pivotIdx >= 0) { if (g2pivotIdx >= 0) { color {atomIndex=g2pivotIdx} @gScheme } g2pivotIdx = _atomPicked color {atomIndex=g2pivotIdx} green } else { g1pivotIdx = _atomPicked color {atomIndex=g1pivotIdx} green } select {gCargoAtoms} } # Bound to ALT-LEFT-CLICK by plicoTug function tugCargoMB() { if (gChain != {atomIndex=_atomPicked}.chain) { clearAtomIdxs() setColors() gChain = {atomIndex=_atomPicked}.chain } # If movable side chain atom picked if (isMovableSideChain( _atomPicked)) { if (gSCidx >= 0) { draw gSCcircle DELETE } if (gSCidx == _atomPicked) { gSCidx = -1 } else { gSCidx = _atomPicked gSCpt = {atomIndex=gSCidx}.xyz draw gSCcircle CIRCLE {atomIndex=gSCidx} MESH NOFILL } } else if ((gChain == "") or ({atomIndex=_atomPicked}.chain == gChain)) { gMinNo = {chain=gChain}.atomno.min gMaxNo = {chain=gChain}.atomno.max if (gNanchorIdx < 0) { gNanchorNo = gMinNo - 1 } if (gCanchorIdx < 0) { gCanchorNo = gMaxNo + 1 } var aPidx = getScBBidx( _atomPicked) gSCidx = -1 draw gSCcircle DELETE # If existing cWard cargo picked if (gCcargoIdx == aPidx) { # Clear the highlight select {atomIndex=gCcargoIdx} halo off # If nWard cargo exists, mark it as the cWard cargo if (gNcargoIdx != gCcargoIdx) { gCcargoIdx = getCpIdx(gNcargoIdx) gCcargoNo = {atomIndex=gCcargoIdx}.atomno } else { gCcargoIdx = -1 gNcargoIdx = -1 } } else if (gNcargoIdx == aPidx) { select {atomIndex=gNcargoIdx} halo off gNcargoIdx = getNmIdx(gCcargoIdx) gNcargoNo = {atomIndex=gNcargoIdx}.atomno } else if (gCcargoIdx >= 0) { var no = {atomIndex=aPidx}.atomno # If pick is nWard of it if (no < {atomIndex=gCcargoIdx}.atomno) { # If exists, clear its highlight if (gNcargoIdx != gCcargoIdx) { select {atomIndex=gNcargoIdx} halo off } # Set new nWard cargo and highlight it gNcargoIdx = getNmIdx(aPidx) gNcargoNo = {atomIndex=gNcargoIdx}.atomno } # Else cWard else { # Clear its old highlight select {atomIndex=gCcargoIdx} if (gNcargoIdx != gCcargoIdx) { halo off } # Set new cWard cargo and highlight gCcargoIdx = getCpIdx(aPidx) gCcargoNo = {atomIndex=gCcargoIdx}.atomno } } # Else no cWard cargo else { # Set new cWard cargo and highlight gCcargoIdx = getCpIdx(aPidx) gCcargoNo = {atomIndex=gCcargoIdx}.atomno gNcargoIdx = getNmIdx(gCcargoIdx) gNcargoNo = {atomIndex=gNcargoIdx}.atomno # Set default cWard anchor at cWard N var iNo = gMaxNo for (; iNo > 0; iNo--) { if ({(atomno=iNo) and (chain=gChain)}.atomName == "N") { break; } } gCanchorIdx = {(atomno=iNo) and (chain=gChain)}.atomIndex gCanchorNo = {atomIndex=gCanchorIdx}.atomno gCanchorXyz = {atomIndex=gCanchorIdx}.xyz } # If any anchor now inside cargo cluster, kill it if ({atomIndex=gCanchorIdx}.atomno <= {atomIndex=gCcargoIdx}.atomno) { gCanchorIdx = -1 gCanchorNo = gMaxNo + 1 } if ({atomIndex=gNanchorIdx}.atomno >= {atomIndex=gNcargoIdx}.atomno) { gNanchorIdx = -1 gNanchorNo = gMinNo - 1 } # Highlight cargo cluster selectNward(gCcargoIdx, gNcargoIdx) gCargoAtoms = {selected} setColors() # Collect the rotor sets collectRotors() # Get connectors between fixed and moving part var aset = {((atomno < gCanchorNo) and (atomno > gNanchorNo) and (chain=gChain))} gAc = (within(kCtolerance, FALSE, {aset}) and not {aset}) } # Enable dragging tugEnableDrag() # Bind other keys bind "SHIFT-LEFT-CLICK" "_pickAtom"; bind "SHIFT-LEFT-CLICK" "+:tugAnchorMB"; bind "ALT-CTRL-LEFT-CLICK" "_pickAtom"; bind "ALT-CTRL-LEFT-CLICK" "+:tugPivotMB"; bind "ALT-SHIFT-LEFT-CLICK" "_pickAtom"; bind "ALT-SHIFT-LEFT-CLICK" "+:tugDestAtomMB"; select {gCargoAtoms} } # Top level of Tug function plicoTug() { set allowModelKit TRUE set allowRotateSelected TRUE set allowMoveAtoms TRUE # Push selected gSelSaves = {selected} select all gZoom = script("show zoom") gRotate = script("show rotation") write tugsave.pdb select none gScheme = defaultColorScheme gAltScheme = ((gScheme == "Jmol") ? "Rasmol" : "Jmol") set echo TOP LEFT background ECHO yellow gEcho = "ALT-CLICK=set cargo range" echo @gEcho gCrotors = array() gNrotors = array() clearAtomIdxs() gChain = "" unbind set picking ON bind "ALT-LEFT-CLICK" "_pickAtom"; bind "ALT-LEFT-CLICK" "+:tugCargoMB"; bind "DOUBLE" "tugExit"; } # Bound to DOUBLE by plicoTug function tugExit() { var p = prompt("Exit tug?", "Yes|No|Undo", TRUE) if (p == "Undo") { load tugsave.pdb script inline gZoom rotate @gRotate echo Tug session undone if (gPlicoRecord != "") { plicoRecord("load tugsave.pdb;") } } if (p != "No") { unbind halo off set allowMoveAtoms FALSE echo select all halo off star off color {selected} @gScheme draw gSCcircle DELETE gBusy = FALSE background ECHO yellow # Pop selected select gSelSaves } } # End of TUG.SPT