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. It also allows the user to move an entire chain to nest against another chain.
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.3 beta 2/13/2014 for Jmol 14 # # Translate or rotate a stretch of a polypeptide against itself by mouse actions # var kTug = 2 var kDtolerance = 0.2 var kAtolerance = 5.0 var kCtolerance = 1.85 var kMtolerance = 0.8 var gCanchorIdx = -1 var gCanchorNo = -1 var gNanchorIdx = -1 var gNanchorNo = -1 var gCcargoIdx = -1 var gNcargoIdx = -1 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 gOkCollide = ({}) var gChain = "" var gMinNo = 1 var gMaxNo = 9999 var gScheme = "Jmol" var gAltScheme = "Rasmol" var gCargoSet = ({}) var gMovingSet = ({}) 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 gZoom = "" var gRotate = "" var gTow = FALSE var g1dynamicIdx = -1 var g2dynamicIdx = -1 var gSCcheck = TRUE # 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, iChain) { while ((iNo >= 0) and ( ({(atomno=iNo) and (chain=iChain)}.atomName != "N") and ({(atomno=iNo) and (chain=iChain)}.atomName != "C") and ({(atomno=iNo) and (chain=iChain)}.atomName != "CA"))) { iNo-- } return iNo } function getNwardBBidx (idx, iChain) { var no = {atomIndex=idx}.atomno - 1 no = getNwardBBno( no, iChain) return ((no >= 0) ? ({(atomno=no) and (chain=iChain)}.atomIndex) : -1) } function getCwardBBno (iNo, iChain) { while ((iNo < gMaxNo) and ( ({(atomno=iNo) and (chain=iChain)}.atomName != "N") and ({(atomno=iNo) and (chain=iChain)}.atomName != "C") and ({(atomno=iNo) and (chain=iChain)}.atomName != "CA"))) { iNo++ } return iNo } function getCwardBBidx (idx, iChain) { var no = {atomIndex=idx}.atomno + 1 no = getCwardBBno( no, iChain) return ((no >= 0) ? ({(atomno=no) and (chain=iChain)}.atomIndex) : -1) } function getScSet (scIdx, iChain) { var scSet = ({}) var idx = getScBBidx(scIdx, iChain) var iNo = {atomIndex=idx}.atomno + 3 for (var i = 1; i < 20; i++) { idx = {(atomno=@{iNo+i}) and (chain=iChain)}.atomIndex if (isBBidx(idx)) { break } scSet = scSet or {atomIndex=idx} } return scSet } function getScBBidx (idx, iChain) { var no = {atomIndex=idx}.atomno for (; no > 0; no--) { if ({(atomno=no) and (chain=iChain)}.atomName == "CA") { break } else if ({(atomno=no) and (chain=iChain)}.atomName == "C") { break } else if ({(atomno=no) and (chain=iChain)}.atomName == "N") { break } else if ({(atomno=no) and (chain=iChain)}.atomName == "CB") { no -= 3 break } } return {(atomno=no) and (chain=iChain)}.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 (not isBBidx(aIDx)) { 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 var iChain = {atomIndex=fromIdx}.chain select none while ({(atomno=iNo) and (chain=iChain)}.atomName != "N") { {(atomno=iNo) and (chain=iChain)}.selected = TRUE iNo++ if (iNo > {chain=iChain}.atomno.max) { break } } } # First and last are BB atoms # Any side atoms in the range are also selected function selectNwardIdx (firstIdx, lastIdx) { var firstno = ((firstIdx < 0) ? {atomIndex=lastIdx}.atomno : {atomIndex=firstIdx}.atomno) var lastno = ((lastIdx < 0) ? firstno : {atomIndex=lastIdx}.atomno) var iChain = ((firstIdx < 0) ? {atomIndex=lastIdx}.chain : {atomIndex=firstIdx}.chain) select (atomno <= firstno) and (atomno >= lastno) and (chain = iChain) if ({(atomno=firstno) and (chain=gChain)}.atomName == "C") { # if psi addSideChainToSelection(firstno-1, TRUE, TRUE) {(atomno=@{firstno+1}) and (chain=iChain)}.selected = TRUE # add O } if ({(atomno=firstno) and (chain=iChain)}.atomName == "CA") { addSideChainToSelection(firstno, TRUE, FALSE) } if ({(atomno=lastno) and (chain=iChain)}.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 selectCwardIdx (firstIdx, lastIdx) { var firstno = ((firstIdx < 0) ? gMaxNo : {atomIndex=firstIdx}.atomno) var lastno = ((lastIdx < 0) ? 1 : {atomIndex=lastIdx}.atomno) var iChain = ((firstIdx < 0) ? {atomIndex=lastIdx}.chain : {atomIndex=firstIdx}.chain) # If nWard anchor in range, begin selection with it if ((gNanchorIdx >= 0) and ({atomIndex=gNanchorIdx}.chain == iChain)) { var aNo = {atomIndex=gNanchorIdx}.atomno if (aNo > firstNo) { firstno = aNo } } # If cWard anchor in range, end selection with it if ((gCanchorIdx >= 0) and ({atomIndex=gCanchorIdx}.chain == iChain)) { var aNo = {atomIndex=gCanchorIdx}.atomno if (aNo < lastNo) { lastno = aNo } } select (atomno >= firstno) and (atomno <= lastno) and (chain = iChain) if ({(atomno=firstno) and (chain=iChain)}.atomName == "C") { # if psi addSideChainToSelection(firstno-1, FALSE, FALSE) } if ({(atomno=lastno) and (chain=iChain)}.atomName == "CA") { addSideChainToSelection(lastno, TRUE, FALSE) } if ({(atomno=lastno) and (chain=iChain)}.atomName == "C") { # if psi addSideChainToSelection(lastno-1, TRUE, TRUE) {(atomno=@{lastno+1}) and (chain=iChain)}.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 cAtoms = ({}) for (var idx = {*}.min.atomIndex; idx <= {*}.max.atomIndex; idx++) { if ({atomIndex=idx}.size > 0) { var lcAtoms = (within(kCtolerance, FALSE, {atomIndex=idx}) and {atomIndex > idx} and not {rc} and not connected({atomIndex=idx})) if (lcAtoms.size > 0) { cAtoms = cAtoms or lcAtoms } } } return cAtoms.size } # Resolve collisions function handleCollisions2( 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, gChain)}}, {atomIndex=idx} , {atomIndex=@{getNwardBBidx(idx, gChain)}}) < 100) { continue } # For all local colliders for (var c = 1; c <= lcAtoms.size; c++ ) { var cidx = lcAtoms[c].atomIndex # If it is with water, delete it if (lcAtoms[c].group = "HOH") { delete {atomIndex=cidx} } # else if it is with side chain not proline, fix it else if (isSCidx(cidx) and ({atomIndex=cidx}.group != "PRO")) { fixSCcollision2(cidx) recollect = TRUE # If not fixed, exit fail if (not gOk2) { return # early exit (break n jmol bug) } } # else if it is itself a side chain not proline, fix it else if (isSCidx(idx) and ({atomIndex=idx}.group != "PRO")) { fixSCcollision2(idx) recollect = TRUE # If not fixed, exit fail if (not gOk2) { return # early exit (break n jmol bug) } } # Else if it is with O, counter-rotate else if (lcAtoms[c].atomName = "O") { counterRotate2(lcAtoms[c].atomIndex, {atomIndex=idx}.xyz, targetIdx, FALSE) # If not fixed, exit fail if (not gOk2) { return # early exit (break n jmol bug) } } # Else if it is itself O, counter-rotate else if ({atomIndex=idx}.atomName = "O") { counterRotate2(idx, lcAtoms[c].xyz, targetIdx, FALSE) # If not fixed, exit fail if (not gOk2) { return # early exit (break n jmol bug) } } else { # Else not fixed, exit fail gOk2 = FALSE return # early exit (break n jmol bug) } } # endfor } } } # 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, gChain)}}, {atomIndex=i1}, {atomIndex=i2}, {atomIndex=i3}) + dt } else { phi = angle({atomIndex=i1}, {atomIndex=i2}, {atomIndex=i3}, {atomIndex=@{getNwardBBidx(i3, gChain)}}) + dt } if ({atomIndex=i2}.atomno > {atomIndex=targetIdx}.atomno) { movePt = TRUE selectNwardIdx(i3, getCwardBBidx(targetIdx, gChain)) {atomIndex=targetIdx}.selected = TRUE } else { selectCwardIdx(i2, targetIdx) } } else { if (({atomIndex=i2}.atomName="CA")) { phi = angle({atomIndex=@{getNwardBBidx(i1, gChain)}}, {atomIndex=i1}, {atomIndex=i2}, {atomIndex=i3}) + dt } else { psi = angle({atomIndex=i2}, {atomIndex=i3}, {atomIndex=i4}, {atomIndex=@{getCwardBBidx(i4, gChain)}}) + dt } if ({atomIndex=i2}.atomno < {atomIndex=targetIdx}.atomno) { movePt = TRUE selectCwardIdx(i3, getNwardBBidx(targetIdx, gChain)) {atomIndex=targetIdx}.selected = TRUE } else { selectNwardIdx(i2, targetIdx) } } # Relax rules if desperate if (pass1 > 10) { phi = -50 } # If rotation within ramachandran limits if ((abs(dt) >= 0.1) and (({atomIndex=i2}.group=="GLY") or (phi < 0))) { # 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 } handleCollisions2( targetIdx) if (not gOk2) { 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 docounterRotate(caPhiIdx, nIdx, cIdx, oIdx, caPsiIdx, dir, nWard) { # Rotate psi {atomIndex=nIdx}.selected = nWard {atomIndex=cIdx}.selected = nWard {atomIndex=oIdx}.selected = nward rotateSelected {atomIndex=caPsiIdx} {atomIndex=cIdx} @{dir} # Counter-rotate phi {atomIndex=nIdx}.selected = not nWard {atomIndex=cIdx}.selected = not nWard {atomIndex=oIdx}.selected = not nward rotateSelected {atomIndex=nIdx} {atomIndex=caPhiIdx} @{-dir} } function counterRotate(oIdx, dir, nWard) { var iChain = {atomIndex=oIdx}.chain var selsave = {selected} var cIdx = getScBBidx(oIdx, iChain) var nIdx = getCwardBBidx(cIdx, iChain) var caPhiIdx = getCwardBBidx(nIdx, iChain) var caPsiIdx = getNwardBBidx(cIdx, iChain) if (nWard) { nNo = {chain=iChain}.atomno.min selectNwardIdx(caPsiIdx, {(atomno=nNo) and (chain=iChain)}.atomIndex) } else { cNo = {chain=iChain}.atomno.max selectCwardIdx(caPhiIdx, {(atomno=cNo) and (chain=iChain)}.atomIndex) } # Counter-rotate docounterRotate(caPhiIdx, nIdx, cIdx, oIdx, caPsiIdx, dir, not nWard) select selsave } function counterRotate2(oIdx, toPt, terminalIdx, oDrag) { var iChain = {atomIndex=oIdx}.chain var selsave = {selected} var gOk2 = TRUE var cIdx = getScBBidx(oIdx, iChain) var nIdx = getCwardBBidx(cIdx, iChain) var caPhiIdx = getCwardBBidx(nIdx, iChain) var caPsiIdx = getNwardBBidx(cIdx, iChain) var nTward = ({atomIndex=oIdx}.atomno < {atomIndex=terminalIdx}.atomno) if (nTward) { selectCwardIdx(cIdx, terminalIdx) } else { selectNwardIdx(nIdx, terminalIdx) } # Until all collisions cancelled var dir = 5 var ang = angle(toPt, {atomIndex=oIdx}, {atomIndex=cIdx}) var tcount = 0 while (oDrag or (within(kCtolerance, FALSE, {atomIndex=oIdx}) and not {atomIndex=oIdx} and not connected({atomIndex=oIdx}) and not {gOkCollide} > 0)) { # Counter-rotate docounterRotate(caPhiIdx, nIdx, cIdx, oIdx, caPsiIdx, dir, nTward) var newang = angle(toPt, {atomIndex=oIdx}, {atomIndex=cIdx}) # If wrong direction once, undo and reverse if (newang > ang) { docounterRotate(caPhiIDx, nIdx, cIdx, oIdx, caPsiIdx, -dir, nTward) # If first time, continue in opposite direction dir *= -1 if (dir < 0) { continue } } if (oDrag) { break } # If no go, undo and exit tcount++ if (tcount > (360/abs(dir))) { gOk2 = FALSE break } } # endwhile select selsave } # Repair proline function repairProline(BBidx) { var cbidx = getCBidx(BBidx) 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 repairSideChain(targetIdx, nWard) { var idx = (nWard ? getCwardBBidx(targetIdx, gChain) : getNwardBBidx(targetIdx, gChain)) 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, gChain), 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, gChain), 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(colliders[i].atomIndex, {atomIndex=dIdx}.xyz, targetIdx, FALSE) } } } } } # Rebuild Cward rotors set function tugTrackC() { # For all bb atoms cWard of cargo var targetIdx = gCcargoIdx var okCount = 0 # Allow collisions with cargo gOkCollide = gCargoSet var tcount = 0 while (targetIdx != gCanchorIdx) { # Step to next atom targetIdx = getCwardBBidx(targetIdx, gChain) # No collision with cargo allowed after two atoms placed if (tcount == 2) { gOkCollide = ({}) } tcount++ # Compute targets desired coords var c1idx = getCwardBBidx(targetIdx, gChain) var n1idx = getNwardBBidx(targetIdx, gChain ) var n2idx = getNwardBBidx(n1Idx, gChain) var n3idx = getNwardBBidx(n2Idx, gChain) 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, 120.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 (not gOK)) { # 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 repairSideChain(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 = gCargoSet var tcount = 0 while (targetIdx != gNanchorIdx) { # Step to next atom targetIdx = getNwardBBidx(targetIdx, gChain) # No collision with cargo allowed after two atoms placed if (tcount == 2) { gOkCollide = ({}) } tcount++ # Compute targets desired coords var n1idx = getNwardBBidx(targetIdx, gChain) var c1idx = getCwardBBidx(targetIdx, gChain) var c2idx = getCwardBBidx(c1idx, gChain) var c3idx = getCwardBBidx(c2idx, gChain) 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 (not gOK)) { # 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 repairSideChain(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, iChain) { var scBondIdxs = array() for (var iNo = no; iNo >= 0; iNo--) { var ile = 0 switch ({(atomno=iNo) and (chain=iChain)}.atomName) { case "CA" : return scBondIdxs # Early exit since break 1 appears broken case "CZ" : if ({(atomno=iNo) and (chain=iChain)}.group == "TYR") { break } case "CE" : if ({(atomno=iNo) and (chain=iChain)}.group == "MET") { break } case "CG1" : if ({(atomno=iNo) and (chain=iChain)}.group == "VAL") { break } if ({(atomno=iNo) and (chain=iChain)}.group == "ILE") { ile = 1 } case "NE" : case "CD" : case "SD" : case "CG" : case "CB" : scBondIdxs += {(atomno=@{iNo+1+ile}) and (chain=iChain)}.atomIndex scBondIdxs += {(atomno=@{iNo+0}) and (chain=iChain)}.atomIndex if ({(atomno=iNo) and (chain=iChain)}.atomName%2 == "CG") { scBondIdxs += {(atomno=@{iNo-1}) and (chain=iChain)}.atomIndex scBondIdxs += {(atomno=@{iNo-4}) and (chain=iChain)}.atomIndex } else if ({(atomno=iNo) and (chain=iChain)}.atomName == "CB") { scBondIdxs += {(atomno=@{iNo-3}) and (chain=iChain)}.atomIndex scBondIdxs += {(atomno=@{iNo-4}) and (chain=iChain)}.atomIndex } else { scBondIdxs += {(atomno=@{iNo-1}) and (chain=iChain)}.atomIndex scBondIdxs += {(atomno=@{iNo-2}) and (chain=iChain)}.atomIndex } break } } return scBondIdxs } # Drag Side Chain function dragSC() { var iNo = {atomIndex=gSCidx}.atomno var iChain = {atomIndex=gSCidx}.chain if ({atomIndex=gSCidx}.group != "PRO") { var scBondIdxs = collectSCrotors( iNo, iChain) var numChi = scBondIdxs.size / 4 var dist = distance({atomIndex=gSCidx}.xyz, gSCpt) var scSet = ({}) if (gSCcheck) { scSet = getScSet(gSCidx, iChain) } # 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) if (gSCcheck) { var colliders = (within(kCtolerance, FALSE, scSet) and not connected(scSet) and not {scSet}) if (colliders.size > 0) { continue } } # 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=iChain)}.atomIndex var icb = {(atomno=@{iNo-1}) and (chain=iChain)}.atomIndex var ica = {(atomno=@{iNo-4}) and (chain=iChain)}.atomIndex var in = {(atomno=@{iNo-5}) and (chain=iChain)}.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 iChain = {atomIndex=idx}.chain var resno = {(atomno=iNo) and (chain=iChain)}.resno # Get SC terminus while (resno == {(atomno=iNo) and (chain=iChain)}.resno) { iNo++ } iNo-- var sc = array() var iBno = iNo while ({(atomno=iBno) and (chain=iChain)}.atomName != "CB") { sc += {(atomno=iBno) and (chain=iChain)} iBno-- } var cbidx = {(atomno=iBno) and (chain=iChain)}.atomIndex var scBondIdxs = collectSCrotors( iNo, iChain) 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[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 } } } } 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) { 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 { 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 } else { gCrotors = rotors } } function collectRotors() { collectBBrotors(FALSE) collectBBrotors(TRUE) } function tugSideChain(pt) { # If destination atom defined if (gDestAtomIdx >= 0) { var 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=g1pivotIdx} green color {atomIndex=g2pivotIdx} green color @gCargoSet @gAltScheme select {(atomIndex=gCcargoIdx) or (atomIndex=gNcargoIdx) or (atomIndex=gCanchorIdx) or (atomIndex=gNanchorIdx)} halo on select {atomIndex=gDestAtomIdx} star on select none } function clearAtomIdxs() { gCcargoIdx = -1 gNcargoIdx = -1 gCanchorIdx = -1 gNanchorIdx = -1 g1pivotIdx = -1 g2pivotIdx = -1 g1dynamicIdx = -1 g2dynamicIdx = -1 gDestAtomIdx = -1 gSCidx = -1 } function timedOut (s) { timeout ID"tug" OFF prompt(s) gBusy = FALSE background ECHO yellow restore state gState select gCargoSet 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("gCcargoIdx = %d;", gCcargoIdx) ls += format("gNcargoIdx = %d;", gNcargoIdx) 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("gOkCollide = %s;", gOkCollide) ls += format("gChain = \"%s\";", gChain) ls += format("gMinNo = %d;", gMinNo) ls += format("gMaxNo = %d;", gMaxNo) ls += format("gCargoSet = %s;", gCargoSet) 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 (not gBusy) { 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 if (not gTow) { gOK = TRUE timeout ID"tug" 20.0 "timedOut(\"Tug timed out\")" 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, gChain) var in = getNwardBBidx(gCanchorIdx, gChain) if ((ic >= 0) and angle({atomIndex=ic}, {atomIndex=gCanchorIdx}, {atomIndex=in}) < 100.0) { gOK = FALSE } } if (gNanchorIdx >= 0) { var ic = getCwardBBidx(gNanchorIdx, gChain) var in = getNwardBBidx(gNanchorIdx, gChain) if ((in >= 0) and angle({atomIndex=ic}, {atomIndex=gNanchorIdx}, {atomIndex=in}) < 100.0) { gOK = FALSE } } } # If too far if (not gOK) { timedOut("TUG TOO FAR!") } # Else OK else { select ((atomno >= gNanchorNo) and (atomno <= gCanchorNo) and (chain = gChain)) var idx = {(atomno=@{{chain=gChain}.atomno.min}) and (chain=gChain)}.atomIndex var ihc = 0 for (ihc = 0; ihc < 10; ihc++) { handleCollisions2( idx) if (countCollisions(({})) == 0) { break } } if (ihc == 10) { var p = prompt("Unable to handle all collisions!") restore state gState } } } select {gCargoSet} gBusy = FALSE background ECHO yellow refresh } } # Bound to ALT-SHIFT-LEFT-DRAG by tugEnableDrag function tugDrag2MB() { tugDragMB(TRUE) } # Bound to ALT-LEFT-DRAG by tugEnableDrag function tugDragMB(alt) { if (not gBusy) { gBusy = TRUE var dx = (40.0 * (_mouseX - gMouseX))/_width var dy = (40.0 * (_mouseY - gMouseY))/_height var q = quaternion() var ptd = {@dx @dy 0} var pt = (!q)%ptd var axis = {0 0 0} if (distance(pt, {0 0 0}) > 0.004) { # If sidechain mode if (gSCidx >= 0) { if ({atomIndex=gSCidx}.atomName == "O") { dir = ((abs(dx) > abs(dy)) ? ((dx < 0) ? 2 : -2) : ((dy < 0) ? 2 : -2)) counterRotate(gSCidx, dir, not alt) } else { gSCcheck = not alt tugSideChain(pt) } } # Else else { # If new drag if (gNewDrag) { gNewDrag = FALSE save state gState } # 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 {gCargoSet} # If pivots defined, rotate it if (g1pivotIdx >= 0) { # If two pivots if (g2pivotIdx >= 0) { axis = {atomIndex=g2pivotIdx} } # Else else { axis = cross(pt, {0 0 0}) + {atomIndex=g1pivotIdx}.xyz } dir = ((abs(dx) > abs(dy)) ? ((dx < 0) ? 2 : -2) : ((dy < 0) ? 2 : -2)) rotateSelectedRecord(g1pivotIdx, axis, dir) } # Else translate it else { translateSelectedRecord(pt) } # If collisions var cNotSels = (within(kCtolerance, FALSE, {selected}) and not {gMovingSet}) if ((cNotSels.size > 0) and (not alt)) { gOk2 = TRUE for (var i = 1; i <= cNotSels.size; i++) { # If net collision vector same as move vector cSels = (within(kCtolerance, FALSE, cNotSels[i]) and {selected}) for (var j = 1; j <= cSels.size; j++) { var v1 = cNotSels[i].xyz - cSels[j].xyz if (abs(angle(v1, {0 0 0}, pt)) < 90) { # If tow mode if (gTow) { # Make a dynamic pivot if (g1pivotIdx < 0) { g1pivotIdx = cSels[j].atomIndex g1dynamicIdx = cNotSels[i].atomIndex color {atomIndex=g1pivotIdx} lightgreen setDistanceIdx(cNotSels[i].atomIndex, cSels[j].atomIndex, kCtolerance + kDtolerance) } else if (g2pivotIdx < 0) { g2pivotIdx = cSels[j].atomIndex g2dynamicIdx = cNotSels[i].atomIndex color {atomIndex=g2pivotIdx} lightgreen setDistanceIdx(cNotSels[i].atomIndex, cSels[j].atomIndex, kCtolerance + kDtolerance) } else { gOk2 = FALSE } } else { # Try to resolve select cSels[j] var idx = {(atomno=@{{chain=gChain}.atomno.min}) and (chain=gChain)}.atomIndex handleCollisions2( idx) } } } # endfor if (not gOk2) { break } } # endfor # If unable if (not gOk2) { # Back off background ECHO pink delay 1 if (g1pivotIdx >= 0) { rotateSelectedRecord(g1pivotIdx, axis, -a) } else { translateSelectedRecord(-pt) } background ECHO yellow } } } # If dynamic pivotsTBD if (g1dynamicIdx >= 0) { var v1 = {atomIndex=g1dynamicIdx}.xyz - {atomIndex=g1pivotIdx}.xyz if (abs(angle(v1, {0 0 0}, pt)) > 90) { color {atomIndex=g1pivotIdx} @gAltScheme g1pivotIdx = -1 g1dynamicIdx = -1 } } if (g2dynamicIdx >= 0) { var v1 = {atomIndex=g2dynamicIdx}.xyz - {atomIndex=g2pivotIdx}.xyz if (abs(angle(v1, {0 0 0}, pt)) > 90) { color {atomIndex=g2pivotIdx} @gAltScheme g2pivotIdx = -1 g2dynamicIdx = -1 } } gMouseX = _mouseX gMouseY = _mouseY } select {gCargoSet} gBusy = FALSE } } # Bound to ALT-LEFT-DOWN by tugEnableDrag function tugMarkMB() { gMouseX = _mouseX gMouseY = _mouseY gNewDrag = TRUE } # Called by tugCargoMB function tugEnableDrag() { gEcho = "__________TUG__________|ALT-CLICK=mark block|SHIFT-CLICK=anchors" + "|ALT-CTRL-CLICK=pivots|ALT-SHIFT-CLICK=dest atom|ALT-DRAG=move" + "|SHIFT-ALT-DRAG=alt move|DOUBLE-CLICK=exit" echo @gEcho # Allow atoms to be dragged bind "ALT-LEFT-DOWN" "tugMarkMB"; bind "ALT-LEFT-UP" "tugDragDoneMB"; bind "ALT-SHIFT-LEFT-DOWN" "tugMarkMB"; bind "ALT-SHIFT-LEFT-UP" "tugDragDoneMB"; bind "ALT-LEFT-DRAG" "tugDragMB"; bind "ALT-SHIFT-LEFT-DRAG" "tugDrag2MB"; unbind "SHIFT-LEFT-CLICK" 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"; } # Bound to SHIFT-LEFT-CLICK by tugCargoMB function tugAnchorMB() { if ({atomIndex=_atomPicked}.chain == gChain) { var aPidx = getScBBidx( _atomPicked, gChain) var pno = {atomIndex=aPidx}.atomno if (pno > {atomIndex=gCcargoIdx}.atomno) { select {atomIndex=gCanchorIdx} halo off if (gCanchorIdx == aPidx) { gCanchorIdx = -1 gCanchorNo = gMaxNo + 1 } else { gCanchorIdx = aPidx gCanchorNo = {atomIndex=gCanchorIdx}.atomno select {atomIndex=gCanchorIdx} halo on } collectBBrotors(FALSE) } else if (pno < {atomIndex=gNcargoIdx}.atomno) { select {atomIndex=gNanchorIdx} halo off if (gNanchorIdx == aPidx) { gNanchorIdx = -1 gNanchorNo = gMinNo - 1 } else { gNanchorIdx = aPidx gNanchorNo = {atomIndex=gNanchorIdx}.atomno select {atomIndex=gNanchorIdx} halo on } collectBBrotors(TRUE) } else { towCargoMB() } # Get moving atoms set gMovingSet = {((atomno < gCanchorNo) and (atomno > gNanchorNo) and (chain=gChain))} } select {gCargoSet} } # 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 {gCargoSet} } } # Bound to CTRL-LEFT-CLICK by tugCargoMB function tugPivotMB() { if (g1pivotIdx == _atomPicked) { color {atomIndex=g1pivotIdx} @gScheme if (g2pivotIdx >= 0) { g1pivotIdx = g2pivotIdx g2pivotIdx = -1 g2dynamicIdx = -1 } else { g1pivotIdx = -1 g1dynamicIdx = -1 } } else if (g2pivotIdx == _atomPicked) { color {atomIndex=g2pivotIdx} @gScheme g2pivotIdx = -1 g2dynamicIdx = -1 } else if (g1pivotIdx >= 0) { if (g2pivotIdx >= 0) { color {atomIndex=g2pivotIdx} @gScheme } g2pivotIdx = _atomPicked g2dynamicIdx = -1 color {atomIndex=g2pivotIdx} green } else { g1pivotIdx = _atomPicked g1dynamicIdx = -1 color {atomIndex=g1pivotIdx} green } select {gCargoSet} } # Bound to SHIFT-LEFT-CLICK by plicoTug function towCargoMB() { gTow = TRUE gChain = {atomIndex=_atomPicked}.chain gMinNo = {chain=gChain}.atomno.min gMaxNo = {chain=gChain}.atomno.max gCcargoIdx = -1 gNcargoIdx = -1 gCanchorIdx = -1 gCanchorNo = gMaxNo + 1 gNanchorIdx = -1 gNanchorNo = gMinNo - 1 # Highlight cargo cluster select {chain=gChain} gCargoSet = {selected} gMovingSet = {selected} setColors() # Enable dragging tugEnableDrag() select {gCargoSet} halo off var es = gEcho.replace("anchors","mark chain") echo @es unbind "SHIFT-LEFT-CLICK" bind "SHIFT-LEFT-CLICK" "_pickAtom"; bind "SHIFT-LEFT-CLICK" "+:towCargoMB"; } # Bound to ALT-LEFT-CLICK by plicoTug function tugCargoMB() { # If O or movable side chain atom picked if (({atomIndex=_atomPicked}.atomName = "O") or (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 ({atomIndex=_atomPicked}.chain != gChain) { if (gTow) { select {chain=gChain} color {selected} @gScheme } gChain = {atomIndex=_atomPicked}.chain select ({atomIndex=gCcargoIdx} or {atomIndex=gNcargoIdx} or {atomIndex=gCanchorIdx} or {atomIndex=gNanchorIdx}) halo off gCcargoIdx = -1 gNcargoIdx = -1 gCanchorIdx = -1 gNanchorIdx = -1 } gTow = FALSE 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, gChain) 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 } # 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 selectNwardIdx(gCcargoIdx, gNcargoIdx) gCargoSet = {selected} setColors() # Collect the rotor sets collectRotors() # Get moving atoms set gMovingSet = {((atomno < gCanchorNo) and (atomno > gNanchorNo) and (chain=gChain))} } # Enable dragging tugEnableDrag() select {gCargoSet} } # Top level of Tug function plicoTug() { # Push selected gSelSaves = {selected} select all # Bad idea to proceed when collisions present while (TRUE) { var cc = countCollisions(({})) if (cc > 0) { var p = prompt(format("%d collision%s present!\nProceed anyway?", cc, ((cc > 1) ? "s" : "")), "OK|Cancel|Repair", TRUE) if (p == "Cancel") { quit } else if (p == "Repair") { select all allSet = {selected} gChain = "XX" for (var idx = {allSet}.atomIndex.min; idx <= {allSet}.atomIndex.max; idx++) { if ({atomIndex=idx}.chain != gChain) { gChain = {atomIndex=idx}.chain select {chain=gChain} handleCollisions2( idx) } } } else { break } } else { break } } # endwhile 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 = ("_________TUG_________|ALT-CLICK=mark block|SHIFT-CLICK=mark chain" + "|DOUBLE-CLICK=exit") echo @gEcho gCrotors = array() gNrotors = array() clearAtomIdxs() gChain = "" unbind bind "ALT-LEFT-CLICK" "_pickAtom"; bind "ALT-LEFT-CLICK" "+:tugCargoMB"; bind "SHIFT-LEFT-CLICK" "_pickAtom"; bind "SHIFT-LEFT-CLICK" "+:towCargoMB"; 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