Difference between revisions of "User:Remig/plico/tug"
< User:Remig | plico
Jump to navigation
Jump to search
m (Add description) |
(Add full chain mode and fix sync issues) |
||
| Line 1: | Line 1: | ||
| − | '''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''' 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: | '''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: | ||
| Line 8: | Line 8: | ||
Copy and paste the following into a text editor and save in your scripts folder as tug.spt. | Copy and paste the following into a text editor and save in your scripts folder as tug.spt. | ||
<pre># tug - Jmol script by Ron Mignery | <pre># tug - Jmol script by Ron Mignery | ||
| − | # v1. | + | # v1.1 beta 2/12/2014 for Jmol 14 |
# | # | ||
| − | # | + | # Translate or rotate a stretch of a polypeptide against itself by mouse actions |
| − | var kTug = | + | # |
| + | var kTug = 2 | ||
var kDtolerance = 0.2 | var kDtolerance = 0.2 | ||
var kAtolerance = 5.0 | var kAtolerance = 5.0 | ||
var kCtolerance = 1.85 | var kCtolerance = 1.85 | ||
var kMtolerance = 0.8 | var kMtolerance = 0.8 | ||
| − | |||
| − | |||
var gCanchorIdx = -1 | var gCanchorIdx = -1 | ||
var gCanchorNo = -1 | var gCanchorNo = -1 | ||
var gNanchorIdx = -1 | var gNanchorIdx = -1 | ||
var gNanchorNo = -1 | var gNanchorNo = -1 | ||
| − | |||
| − | |||
| − | |||
| − | |||
var gCcargoIdx = -1 | var gCcargoIdx = -1 | ||
var gNcargoIdx = -1 | var gNcargoIdx = -1 | ||
| − | |||
| − | |||
var gCcargoNo = -1 | var gCcargoNo = -1 | ||
var gNcargoNo = -1 | var gNcargoNo = -1 | ||
| Line 35: | Line 28: | ||
var g1pivotIdx = -1 | var g1pivotIdx = -1 | ||
var g2pivotIdx = -1 | var g2pivotIdx = -1 | ||
| − | var gSelSaves = ({}) | + | var gSelSaves = ({}) |
var gCrotors = array() | var gCrotors = array() | ||
| − | var gNrotors = array() | + | var gNrotors = array() |
var gMouseX = 0 | var gMouseX = 0 | ||
var gMouseY = 0 | var gMouseY = 0 | ||
| − | var | + | var gOkCollide = ({}) |
var gChain = "" | var gChain = "" | ||
| − | var gMinNo = 1 | + | var gMinNo = 1 |
| − | var gMaxNo = 9999 | + | var gMaxNo = 9999 |
var gScheme = "Jmol" | var gScheme = "Jmol" | ||
var gAltScheme = "Rasmol" | var gAltScheme = "Rasmol" | ||
| − | var | + | var gCargoSet = ({}) |
| − | var | + | var gMovingSet = ({}) |
var gBusy = FALSE | var gBusy = FALSE | ||
var gSCidx = -1 | var gSCidx = -1 | ||
| Line 57: | Line 50: | ||
var gNewDrag = FALSE | var gNewDrag = FALSE | ||
var gEcho = "" | var gEcho = "" | ||
| − | |||
var gZoom = "" | var gZoom = "" | ||
var gRotate = "" | var gRotate = "" | ||
| + | var gTow = FALSE | ||
| + | var g1dynamicIdx = -1 | ||
| + | var g2dynamicIdx = -1 | ||
# Return L tetrahedron point if i1<i2<i3, else R point | # Return L tetrahedron point if i1<i2<i3, else R point | ||
| Line 266: | Line 261: | ||
var ret = FALSE | var ret = FALSE | ||
if (isBBidx(aIDx) == FALSE) { | if (isBBidx(aIDx) == FALSE) { | ||
| − | + | ||
ret = TRUE | ret = TRUE | ||
switch({atomIndex=aIdx}.atomName) { | switch({atomIndex=aIdx}.atomName) { | ||
| Line 285: | Line 280: | ||
{(atomno=iNo) and (chain=gChain)}.selected = addOXT | {(atomno=iNo) and (chain=gChain)}.selected = addOXT | ||
} | } | ||
| − | iNo++ | + | iNo++ |
} | } | ||
} | } | ||
| Line 291: | Line 286: | ||
function selectAddSideChain(fromIdx) { | function selectAddSideChain(fromIdx) { | ||
var iNo = {atomIndex=fromIdx}.atomno | var iNo = {atomIndex=fromIdx}.atomno | ||
| + | var iChain = {atomIndex=fromIdx}.chain | ||
select none | select none | ||
| − | while ({(atomno=iNo) and (chain= | + | while ({(atomno=iNo) and (chain=iChain)}.atomName != "N") { |
| − | {(atomno=iNo) and (chain= | + | {(atomno=iNo) and (chain=iChain)}.selected = TRUE |
| − | iNo++ | + | iNo++ |
| − | if (iNo > | + | if (iNo > {chain=iChain}.atomno.max) { |
break | break | ||
| − | } | + | } |
} | } | ||
} | } | ||
| Line 303: | Line 299: | ||
# First and last are BB atoms | # First and last are BB atoms | ||
# Any side atoms in the range are also selected | # Any side atoms in the range are also selected | ||
| − | function | + | function selectNwardIdx (firstIdx, lastIdx) { |
var firstno = ((firstIdx < 0) ? {atomIndex=lastIdx}.atomno : {atomIndex=firstIdx}.atomno) | var firstno = ((firstIdx < 0) ? {atomIndex=lastIdx}.atomno : {atomIndex=firstIdx}.atomno) | ||
var lastno = ((lastIdx < 0) ? firstno : {atomIndex=lastIdx}.atomno) | var lastno = ((lastIdx < 0) ? firstno : {atomIndex=lastIdx}.atomno) | ||
| − | + | var iChain = ((firstIdx < 0) | |
| − | select (atomno <= firstno) and (atomno >= lastno) | + | ? {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 | if ({(atomno=firstno) and (chain=gChain)}.atomName == "C") { # if psi | ||
addSideChainToSelection(firstno-1, TRUE, TRUE) | addSideChainToSelection(firstno-1, TRUE, TRUE) | ||
| − | {(atomno=@{firstno+1}) and (chain= | + | {(atomno=@{firstno+1}) and (chain=iChain)}.selected = TRUE # add O |
} | } | ||
| − | if ({(atomno=firstno) and (chain= | + | if ({(atomno=firstno) and (chain=iChain)}.atomName == "CA") { |
addSideChainToSelection(firstno, TRUE, FALSE) | addSideChainToSelection(firstno, TRUE, FALSE) | ||
} | } | ||
| − | if ({(atomno=lastno) and (chain= | + | if ({(atomno=lastno) and (chain=iChain)}.atomName == "C") { # if psi |
addSideChainToSelection(lastno-1, FALSE, FALSE) | addSideChainToSelection(lastno-1, FALSE, FALSE) | ||
} | } | ||
| Line 323: | Line 321: | ||
# First and last are BB atoms | # First and last are BB atoms | ||
# Any side atoms in the range are also selected | # Any side atoms in the range are also selected | ||
| − | function | + | function selectCwardIdx (firstIdx, lastIdx) { |
var firstno = ((firstIdx < 0) ? gMaxNo : {atomIndex=firstIdx}.atomno) | var firstno = ((firstIdx < 0) ? gMaxNo : {atomIndex=firstIdx}.atomno) | ||
var lastno = ((lastIdx < 0) ? 1 : {atomIndex=lastIdx}.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 nWard anchor in range, begin selection with it | ||
| − | if (gNanchorIdx >= 0) { | + | if ((gNanchorIdx >= 0) and ({atomIndex=gNanchorIdx}.chain == iChain)) { |
var aNo = {atomIndex=gNanchorIdx}.atomno | var aNo = {atomIndex=gNanchorIdx}.atomno | ||
if (aNo > firstNo) { | if (aNo > firstNo) { | ||
| Line 334: | Line 334: | ||
} | } | ||
} | } | ||
| − | + | ||
# If cWard anchor in range, end selection with it | # If cWard anchor in range, end selection with it | ||
| − | if (gCanchorIdx >= 0) { | + | if ((gCanchorIdx >= 0) and ({atomIndex=gCanchorIdx}.chain == iChain)) { |
var aNo = {atomIndex=gCanchorIdx}.atomno | var aNo = {atomIndex=gCanchorIdx}.atomno | ||
if (aNo < lastNo) { | if (aNo < lastNo) { | ||
| Line 342: | Line 342: | ||
} | } | ||
} | } | ||
| − | + | ||
| − | select (atomno >= firstno) and (atomno <= lastno) | + | select (atomno >= firstno) and (atomno <= lastno) and (chain = iChain) |
| − | + | ||
| − | if ({(atomno=firstno) and (chain= | + | if ({(atomno=firstno) and (chain=iChain)}.atomName == "C") { # if psi |
addSideChainToSelection(firstno-1, FALSE, FALSE) | addSideChainToSelection(firstno-1, FALSE, FALSE) | ||
} | } | ||
| − | if ({(atomno=lastno) and (chain= | + | if ({(atomno=lastno) and (chain=iChain)}.atomName == "CA") { |
addSideChainToSelection(lastno, TRUE, FALSE) | addSideChainToSelection(lastno, TRUE, FALSE) | ||
} | } | ||
| − | if ({(atomno=lastno) and (chain= | + | if ({(atomno=lastno) and (chain=iChain)}.atomName == "C") { # if psi |
addSideChainToSelection(lastno-1, TRUE, TRUE) | addSideChainToSelection(lastno-1, TRUE, TRUE) | ||
| − | {(atomno=@{lastno+1}) and (chain= | + | {(atomno=@{lastno+1}) and (chain=iChain)}.selected = TRUE # add O |
} | } | ||
} | } | ||
| Line 398: | Line 398: | ||
function countCollisions(rc) { | function countCollisions(rc) { | ||
| − | var | + | var cAtoms = ({}) |
for (var idx = {*}.min.atomIndex; idx <= {*}.max.atomIndex; idx++) { | for (var idx = {*}.min.atomIndex; idx <= {*}.max.atomIndex; idx++) { | ||
| − | lcAtoms = | + | 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 = cAtom or lcAtoms | ||
| + | } | ||
| + | } | ||
} | } | ||
| − | return | + | return cAtoms.size |
} | } | ||
# Resolve collisions | # Resolve collisions | ||
| − | function | + | function handleCollisions2( targetIdx) { |
# For all selected atoms | # For all selected atoms | ||
| Line 415: | Line 420: | ||
var idx = {(atomno=iNo) and (chain=gchain)}.atomIndex | var idx = {(atomno=iNo) and (chain=gchain)}.atomIndex | ||
if ({atomindex=idx}.selected) { | if ({atomindex=idx}.selected) { | ||
| − | + | ||
# Collect local colliders | # Collect local colliders | ||
var lcAtoms = (within(kCtolerance, FALSE, {atomIndex=idx}) | var lcAtoms = (within(kCtolerance, FALSE, {atomIndex=idx}) | ||
| Line 421: | Line 426: | ||
and not {gOkCollide} | and not {gOkCollide} | ||
and not connected({atomIndex=idx})) | and not connected({atomIndex=idx})) | ||
| − | |||
if (lcAtoms.size > 0) { | if (lcAtoms.size > 0) { | ||
| − | + | ||
# Ignore kinked BB | # Ignore kinked BB | ||
if (isBBidx(idx) and angle({atomIndex=@{getCwardBBidx(idx)}}, | if (isBBidx(idx) and angle({atomIndex=@{getCwardBBidx(idx)}}, | ||
| Line 429: | Line 433: | ||
continue | continue | ||
} | } | ||
| − | + | ||
| − | + | # For all local colliders | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | # For all local | ||
| − | |||
for (var c = 1; c <= lcAtoms.size; c++ ) { | 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") { | if (lcAtoms[c].group = "HOH") { | ||
| − | delete {atomIndex= | + | 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) | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | fixSCcollision2(cidx) | ||
recollect = TRUE | recollect = TRUE | ||
| − | + | ||
# If not fixed, exit fail | # If not fixed, exit fail | ||
if (gOk2 == FALSE) { | if (gOk2 == FALSE) { | ||
| Line 467: | Line 453: | ||
} | } | ||
} | } | ||
| − | + | ||
| − | + | # 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 fixed, exit fail | ||
if (gOk2 == FALSE) { | if (gOk2 == FALSE) { | ||
| Line 489: | Line 464: | ||
} | } | ||
} | } | ||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | # Rotate rotor set to move target atom to its proper place | + | # Else if it is with O, counter-rotate |
| − | function tugTrackIdx(targetIdx, targetPt, nWard, cDetect) { | + | else if (lcAtoms[c].atomName = "O") { |
| + | counterRotate2(lcAtoms[c].atomIndex, | ||
| + | {atomIndex=idx}.xyz, targetIdx, FALSE) | ||
| + | |||
| + | # If not fixed, exit fail | ||
| + | if (gOk2 == FALSE) { | ||
| + | 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 (gOk2 == FALSE) { | ||
| + | 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 | gOK = FALSE | ||
var pt = targetPt | var pt = targetPt | ||
| Line 502: | Line 503: | ||
var rotors = (nWard ? gNrotors : gCrotors) | var rotors = (nWard ? gNrotors : gCrotors) | ||
| + | |||
# For a number of passes | # For a number of passes | ||
for (var pass1 = 0; pass1 < 20; pass1++) { | for (var pass1 = 0; pass1 < 20; pass1++) { | ||
var blocked = ({}) | var blocked = ({}) | ||
for (var pass2 = 0; pass2 < (rotors.size/4); pass2++) { | for (var pass2 = 0; pass2 < (rotors.size/4); pass2++) { | ||
| − | + | ||
var v1 = {atomIndex=targetIdx}.xyz - pt | var v1 = {atomIndex=targetIdx}.xyz - pt | ||
| − | + | ||
# Find the most orthgonal unused rotor | # Find the most orthgonal unused rotor | ||
var imax = 0 | var imax = 0 | ||
| Line 519: | Line 521: | ||
if ({blocked and {atomIndex=i2}}.count == 0) { | if ({blocked and {atomIndex=i2}}.count == 0) { | ||
var v2 = {atomIndex=i3}.xyz - {atomIndex=i2}.xyz | var v2 = {atomIndex=i3}.xyz - {atomIndex=i2}.xyz | ||
| − | + | ||
var s = sin(abs(angle(v1, {0 0 0}, v2))) | var s = sin(abs(angle(v1, {0 0 0}, v2))) | ||
if (s > smax) { | if (s > smax) { | ||
| Line 528: | Line 530: | ||
} | } | ||
} | } | ||
| − | + | ||
# If no more rotors, break to next full try | # If no more rotors, break to next full try | ||
if (imax == 0) { | if (imax == 0) { | ||
| Line 537: | Line 539: | ||
var i3 = rotors[imax+2] | var i3 = rotors[imax+2] | ||
var i4 = rotors[imax+3] | var i4 = rotors[imax+3] | ||
| − | + | ||
# Get dihedral of rotor with target point | # Get dihedral of rotor with target point | ||
var dt = angle({atomIndex=targetIdx}, {atomIndex=i2}, {atomIndex=i3}, pt) | var dt = angle({atomIndex=targetIdx}, {atomIndex=i2}, {atomIndex=i3}, pt) | ||
| Line 546: | Line 548: | ||
var psi = dh + dt | var psi = dh + dt | ||
var phi = dh + dt | var phi = dh + dt | ||
| − | + | ||
# Compute resultant psi and phi | # Compute resultant psi and phi | ||
# and select from target atom to first half of rotor | # and select from target atom to first half of rotor | ||
| Line 559: | Line 561: | ||
{atomIndex=i3}, {atomIndex=@{getNwardBBidx(i3)}}) + dt | {atomIndex=i3}, {atomIndex=@{getNwardBBidx(i3)}}) + dt | ||
} | } | ||
| − | + | ||
if ({atomIndex=i2}.atomno > {atomIndex=targetIdx}.atomno) { | if ({atomIndex=i2}.atomno > {atomIndex=targetIdx}.atomno) { | ||
movePt = TRUE | movePt = TRUE | ||
| − | + | selectNwardIdx(i3, getCwardBBidx(targetIdx)) | |
{atomIndex=targetIdx}.selected = TRUE | {atomIndex=targetIdx}.selected = TRUE | ||
} | } | ||
else { | else { | ||
| − | + | selectCwardIdx(i2, targetIdx) | |
} | } | ||
} | } | ||
| Line 578: | Line 580: | ||
{atomIndex=i4}, {atomIndex=@{getCwardBBidx(i4)}}) + dt | {atomIndex=i4}, {atomIndex=@{getCwardBBidx(i4)}}) + dt | ||
} | } | ||
| − | + | ||
if ({atomIndex=i2}.atomno < {atomIndex=targetIdx}.atomno) { | if ({atomIndex=i2}.atomno < {atomIndex=targetIdx}.atomno) { | ||
movePt = TRUE | movePt = TRUE | ||
| − | + | selectCwardIdx(i3, getNwardBBidx(targetIdx)) | |
{atomIndex=targetIdx}.selected = TRUE | {atomIndex=targetIdx}.selected = TRUE | ||
} | } | ||
else { | else { | ||
| − | + | selectNwardIdx(i2, targetIdx) | |
} | } | ||
} | } | ||
| − | + | ||
| + | # Relax rules if desperate | ||
| + | if (pass1 > 10) { | ||
| + | phi = -50 | ||
| + | } | ||
| + | |||
# If rotation within ramachandran limits | # If rotation within ramachandran limits | ||
| − | + | if ((abs(dt) >= 0.1) and | |
| − | if ((abs(dt) >= 0.1) and | + | (({atomIndex=i2}.group=="GLY") or (phi < 0))) { |
| − | (({atomIndex=i2}.group=="GLY") or (phi < 0 | ||
# If moving target point, put the target atom there | # If moving target point, put the target atom there | ||
| Line 600: | Line 606: | ||
{atomIndex=targetIdx}.xyz = pt | {atomIndex=targetIdx}.xyz = pt | ||
} | } | ||
| − | + | ||
# Rotate to minimize vector ==================== | # Rotate to minimize vector ==================== | ||
rotateSelected {atomIndex=i2} {atomIndex=i3} @dt | rotateSelected {atomIndex=i2} {atomIndex=i3} @dt | ||
| Line 606: | Line 612: | ||
# If collision checking | # If collision checking | ||
if (cDetect) { | if (cDetect) { | ||
| − | + | ||
# If collision, back off by eighths | # If collision, back off by eighths | ||
var wasCollision = FALSE | var wasCollision = FALSE | ||
| Line 612: | Line 618: | ||
if (ci < 3) { | if (ci < 3) { | ||
dt /= 2 | dt /= 2 | ||
| − | } | + | } |
| − | + | handleCollisions2( nWard, targetIdx) | |
if (gOk2==FALSE) { | if (gOk2==FALSE) { | ||
wasCollision = TRUE | wasCollision = TRUE | ||
| Line 626: | Line 632: | ||
break | break | ||
} | } | ||
| − | + | ||
if (dt < 0.01) { | if (dt < 0.01) { | ||
break | break | ||
| Line 632: | Line 638: | ||
} # endfor | } # endfor | ||
} | } | ||
| − | + | ||
# If moving target point, put the target atom back | # If moving target point, put the target atom back | ||
if (movePt) { | if (movePt) { | ||
| Line 638: | Line 644: | ||
{atomIndex=targetIdx}.xyz = cp | {atomIndex=targetIdx}.xyz = cp | ||
} | } | ||
| − | + | ||
} | } | ||
| − | + | ||
# If close enough, stop | # If close enough, stop | ||
if (distance(pt, {atomIndex=targetIdx}) < kDtolerance) { | if (distance(pt, {atomIndex=targetIdx}) < kDtolerance) { | ||
| Line 647: | Line 653: | ||
break | break | ||
} | } | ||
| − | + | ||
# Block rotor | # Block rotor | ||
blocked |= {atomIndex=i2} | blocked |= {atomIndex=i2} | ||
| − | + | ||
} # endfor num rotors passes | } # endfor num rotors passes | ||
| − | + | ||
if (gOK) { | if (gOK) { | ||
break | break | ||
| Line 660: | Line 666: | ||
# Counter rotate bonds on either side of a BB O | # Counter rotate bonds on either side of a BB O | ||
| − | function | + | function docounterRotate(caPhiIdx, nIdx, cIdx, oIdx, caPsiIdx, dir, nWard) { |
| − | # Rotate | + | # Rotate psi |
{atomIndex=nIdx}.selected = nWard | {atomIndex=nIdx}.selected = nWard | ||
{atomIndex=cIdx}.selected = nWard | {atomIndex=cIdx}.selected = nWard | ||
| − | {atomIndex=oIdx}.selected = | + | {atomIndex=oIdx}.selected = nward |
rotateSelected {atomIndex=caPsiIdx} {atomIndex=cIdx} @{dir} | rotateSelected {atomIndex=caPsiIdx} {atomIndex=cIdx} @{dir} | ||
| − | # Counter-rotate | + | # Counter-rotate phi |
{atomIndex=nIdx}.selected = not nWard | {atomIndex=nIdx}.selected = not nWard | ||
{atomIndex=cIdx}.selected = not nWard | {atomIndex=cIdx}.selected = not nWard | ||
| − | {atomIndex=oIdx}.selected = not | + | {atomIndex=oIdx}.selected = not nward |
rotateSelected {atomIndex=nIdx} {atomIndex=caPhiIdx} @{-dir} | rotateSelected {atomIndex=nIdx} {atomIndex=caPhiIdx} @{-dir} | ||
} | } | ||
| − | + | ||
| − | function | + | function counterRotate(oIdx, dir, nWard) { |
| + | |||
var selsave = {selected} | var selsave = {selected} | ||
| − | + | var iChain = {atomIndex=oIdx}.chain | |
| − | |||
| − | var | ||
| − | |||
| − | |||
| − | |||
| − | |||
var cIdx = getScBBidx(oIdx) | var cIdx = getScBBidx(oIdx) | ||
var nIdx = getCwardBBidx(cIdx) | var nIdx = getCwardBBidx(cIdx) | ||
var caPhiIdx = getCwardBBidx(nIdx) | var caPhiIdx = getCwardBBidx(nIdx) | ||
var caPsiIdx = getNwardBBidx(cIdx) | var caPsiIdx = getNwardBBidx(cIdx) | ||
| − | + | ||
| − | |||
if (nWard) { | if (nWard) { | ||
| − | + | nNo = {chain=iChain}.atomno.min | |
| + | selectNwardIdx(caPsiIdx, {(atomno=nNo) and (chain=iChain)}.atomIndex) | ||
} | } | ||
else { | 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 selsave = {selected} | ||
| + | var gOk2 = TRUE | ||
| + | var cIdx = getScBBidx(oIdx) | ||
| + | var nIdx = getCwardBBidx(cIdx) | ||
| + | var caPhiIdx = getCwardBBidx(nIdx) | ||
| + | var caPsiIdx = getNwardBBidx(cIdx) | ||
| + | |||
| + | var nTward = ({atomIndex=oIdx}.atomno < {atomIndex=terminalIdx}.atomno) | ||
| + | if (nTward) { | ||
| + | selectCwardIdx(cIdx, terminalIdx) | ||
| + | } | ||
| + | else { | ||
| + | selectNwardIdx(nIdx, terminalIdx) | ||
| + | } | ||
| + | |||
# Until all collisions cancelled | # Until all collisions cancelled | ||
var dir = 5 | var dir = 5 | ||
| − | var ang = angle( | + | var ang = angle(toPt, {atomIndex=oIdx}, {atomIndex=cIdx}) |
var tcount = 0 | var tcount = 0 | ||
| − | while (within(kCtolerance, FALSE, {atomIndex=oIdx}) | + | while (oDrag or (within(kCtolerance, FALSE, {atomIndex=oIdx}) |
and not {atomIndex=oIdx} and not connected({atomIndex=oIdx}) | and not {atomIndex=oIdx} and not connected({atomIndex=oIdx}) | ||
| − | and not {gOkCollide} > 0) { | + | and not {gOkCollide} > 0)) { |
| − | + | ||
# Counter-rotate | # Counter-rotate | ||
| − | + | docounterRotate(caPhiIdx, nIdx, cIdx, oIdx, caPsiIdx, dir, nTward) | |
| − | var newang = angle( | + | var newang = angle(toPt, {atomIndex=oIdx}, {atomIndex=cIdx}) |
| − | + | ||
# If wrong direction once, undo and reverse | # If wrong direction once, undo and reverse | ||
if (newang > ang) { | if (newang > ang) { | ||
| − | + | docounterRotate(caPhiIDx, nIdx, cIdx, oIdx, caPsiIdx, -dir, nTward) | |
| − | + | ||
# If first time, continue in opposite direction | # If first time, continue in opposite direction | ||
dir *= -1 | dir *= -1 | ||
| Line 718: | Line 742: | ||
continue | continue | ||
} | } | ||
| + | } | ||
| + | |||
| + | if (oDrag) { | ||
| + | break | ||
} | } | ||
| Line 726: | Line 754: | ||
break | break | ||
} | } | ||
| − | + | ||
} # endwhile | } # endwhile | ||
| − | select selsave | + | select selsave |
} | } | ||
# Repair proline | # Repair proline | ||
| − | function repairProline( | + | function repairProline(BBidx) { |
| − | var cbidx = getCBidx( | + | var cbidx = getCBidx(BBidx) |
var cbno = {atomIndex=cbidx}.atomno | var cbno = {atomIndex=cbidx}.atomno | ||
var cgidx = {(atomno=@{cbno+1}) and (chain=gChain)}.atomIndex | var cgidx = {(atomno=@{cbno+1}) and (chain=gChain)}.atomIndex | ||
| Line 739: | Line 767: | ||
var caidx = {(atomno=@{cbno-3}) and (chain=gChain)}.atomIndex | var caidx = {(atomno=@{cbno-3}) and (chain=gChain)}.atomIndex | ||
var nidx = {(atomno=@{cbno-4}) and (chain=gChain)}.atomIndex | var nidx = {(atomno=@{cbno-4}) and (chain=gChain)}.atomIndex | ||
| − | + | ||
select {atomIndex=cbidx} | select {atomIndex=cbidx} | ||
setAngleIdx(nidx, caidx, cbidx, 109.5) | setAngleIdx(nidx, caidx, cbidx, 109.5) | ||
| − | + | ||
select {atomIndex=cdidx} | select {atomIndex=cdidx} | ||
setDistanceIdx(nidx, cdidx, 1.47) | setDistanceIdx(nidx, cdidx, 1.47) | ||
setAngleIdx(caidx, nidx, cdidx, 102.7) | setAngleIdx(caidx, nidx, cdidx, 102.7) | ||
setDihedralIdx(cbidx, caidx, nidx, cdidx, 16.2) | setDihedralIdx(cbidx, caidx, nidx, cdidx, 16.2) | ||
| − | + | ||
select {atomIndex=cgidx} | select {atomIndex=cgidx} | ||
setDistanceIdx(cdidx, cgidx, 1.51) | setDistanceIdx(cdidx, cgidx, 1.51) | ||
| Line 755: | Line 783: | ||
# Repair side chain | # Repair side chain | ||
| − | function | + | function repairSideChain(targetIdx, nWard) { |
var idx = (nWard ? getCwardBBidx(targetIdx) : getNwardBBidx(targetIdx)) | var idx = (nWard ? getCwardBBidx(targetIdx) : getNwardBBidx(targetIdx)) | ||
| Line 783: | Line 811: | ||
} | } | ||
} | } | ||
| − | + | ||
else if ({atomIndex=targetIdx}.atomName == "C") { | else if ({atomIndex=targetIdx}.atomName == "C") { | ||
var oidx = getOidx(targetIdx) | var oidx = getOidx(targetIdx) | ||
| Line 801: | Line 829: | ||
for (var i = 1; i <= colliders.size; i++) { | for (var i = 1; i <= colliders.size; i++) { | ||
if (colliders[i].atomName == "O") { | if (colliders[i].atomName == "O") { | ||
| − | counterRotate2( | + | counterRotate2(colliders[i].atomIndex, |
| + | {atomIndex=dIdx}.xyz, targetIdx, FALSE) | ||
} | } | ||
} | } | ||
| Line 814: | Line 843: | ||
var targetIdx = gCcargoIdx | var targetIdx = gCcargoIdx | ||
var okCount = 0 | var okCount = 0 | ||
| − | + | ||
# Allow collisions with cargo | # Allow collisions with cargo | ||
| − | gOkCollide = | + | gOkCollide = gCargoSet |
| − | var tcount = 0 | + | var tcount = 0 |
while (targetIdx != gCanchorIdx) { | while (targetIdx != gCanchorIdx) { | ||
| − | + | ||
# Step to next atom | # Step to next atom | ||
targetIdx = getCwardBBidx(targetIdx) | targetIdx = getCwardBBidx(targetIdx) | ||
| − | + | ||
# No collision with cargo allowed after two atoms placed | # No collision with cargo allowed after two atoms placed | ||
if (tcount == 2) { | if (tcount == 2) { | ||
| Line 828: | Line 857: | ||
} | } | ||
tcount++ | tcount++ | ||
| − | + | ||
# Compute targets desired coords | # Compute targets desired coords | ||
var c1idx = getCwardBBidx(targetIdx) | var c1idx = getCwardBBidx(targetIdx) | ||
| Line 838: | Line 867: | ||
var oidx = getOidx(n1idx) | var oidx = getOidx(n1idx) | ||
select {atomIndex=oidx} | select {atomIndex=oidx} | ||
| − | + | ||
| − | # Desired target location is trigonal O | + | # Desired target location is trigonal O |
setDistanceIdx(n1idx, oidx, 1.5) | setDistanceIdx(n1idx, oidx, 1.5) | ||
pt = getTrigonal(n2idx, n1idx, oidx, 1.37) | pt = getTrigonal(n2idx, n1idx, oidx, 1.37) | ||
| Line 846: | Line 875: | ||
else if (({atomIndex=targetIdx}.atomName == "C") | else if (({atomIndex=targetIdx}.atomName == "C") | ||
and ({atomIndex=targetIdx}.group != "GLY")) { | and ({atomIndex=targetIdx}.group != "GLY")) { | ||
| − | + | ||
# Desired target location is tetragonal CB | # Desired target location is tetragonal CB | ||
var cbidx = getCBidx(n1idx) | var cbidx = getCBidx(n1idx) | ||
| Line 852: | Line 881: | ||
} | } | ||
else { # CA (or GLY C) | else { # CA (or GLY C) | ||
| − | + | ||
# Save current target coords | # Save current target coords | ||
var cp = {atomIndex=targetIdx}.xyz | var cp = {atomIndex=targetIdx}.xyz | ||
| − | + | ||
# Set target atom at desired distance and angle | # Set target atom at desired distance and angle | ||
select {atomIndex=targetIdx} | select {atomIndex=targetIdx} | ||
setDistanceIdx(n1idx, targetIdx, 1.5) | setDistanceIdx(n1idx, targetIdx, 1.5) | ||
| − | setAngleIdx(n2idx, n1idx, targetIdx, | + | setAngleIdx(n2idx, n1idx, targetIdx, 120.0) |
if ({atomIndex=targetIdx}.atomName == "CA") { | if ({atomIndex=targetIdx}.atomName == "CA") { | ||
setDihedralIdx(n3idx, n2idx, n1idx, targetIdx, 180) | setDihedralIdx(n3idx, n2idx, n1idx, targetIdx, 180) | ||
} | } | ||
| − | + | ||
# Record and restore target | # Record and restore target | ||
pt = {atomIndex=targetIdx}.xyz | pt = {atomIndex=targetIdx}.xyz | ||
| Line 869: | Line 898: | ||
} | } | ||
| − | # If target not at desired location | + | # If target not at desired location |
if (distance(pt, {atomIndex=targetIdx}) > kDtolerance) { | if (distance(pt, {atomIndex=targetIdx}) > kDtolerance) { | ||
okCount = 0 | okCount = 0 | ||
| Line 876: | Line 905: | ||
gOK = FALSE | gOK = FALSE | ||
while ((xcount < 20) and (gOK == FALSE)) { | while ((xcount < 20) and (gOK == FALSE)) { | ||
| − | + | ||
# Rotate on cWard rotor set to move it there | # Rotate on cWard rotor set to move it there | ||
tugTrackIdx(targetIdx, pt, FALSE, FALSE) | tugTrackIdx(targetIdx, pt, FALSE, FALSE) | ||
| Line 886: | Line 915: | ||
gOK = TRUE | gOK = TRUE | ||
okCount++ | okCount++ | ||
| − | } | + | } |
| − | + | ||
# If successful | # If successful | ||
if (gOK == TRUE) { | if (gOK == TRUE) { | ||
| − | + | ||
# Adust any side atoms | # Adust any side atoms | ||
| − | + | repairSideChain(targetIdx, FALSE) | |
} | } | ||
| − | + | ||
# Else fail | # Else fail | ||
else { | else { | ||
break | break | ||
} | } | ||
| − | + | ||
# If no movement in 4 tries, we are done | # If no movement in 4 tries, we are done | ||
if (okCount > 3) { | if (okCount > 3) { | ||
| Line 911: | Line 940: | ||
gOK = TRUE | gOK = TRUE | ||
| − | + | ||
# For all bb atoms nWard of cargo | # For all bb atoms nWard of cargo | ||
var targetIdx = gNcargoIdx | var targetIdx = gNcargoIdx | ||
var okCount = 0 | var okCount = 0 | ||
| − | + | ||
# Allow collisions with cargo | # Allow collisions with cargo | ||
| − | gOkCollide = | + | gOkCollide = gCargoSet |
| − | var tcount = 0 | + | var tcount = 0 |
while (targetIdx != gNanchorIdx) { | while (targetIdx != gNanchorIdx) { | ||
# Step to next atom | # Step to next atom | ||
targetIdx = getNwardBBidx(targetIdx) | targetIdx = getNwardBBidx(targetIdx) | ||
| − | + | ||
# No collision with cargo allowed after two atoms placed | # No collision with cargo allowed after two atoms placed | ||
if (tcount == 2) { | if (tcount == 2) { | ||
| Line 929: | Line 958: | ||
} | } | ||
tcount++ | tcount++ | ||
| − | + | ||
# Compute targets desired coords | # Compute targets desired coords | ||
var n1idx = getNwardBBidx(targetIdx) | var n1idx = getNwardBBidx(targetIdx) | ||
| Line 937: | Line 966: | ||
var pt = {0 0 0} | var pt = {0 0 0} | ||
if ({atomIndex=targetIdx}.atomName == "CA") { | if ({atomIndex=targetIdx}.atomName == "CA") { | ||
| − | + | ||
| − | # Desired target location is trigonal O | + | # Desired target location is trigonal O |
var oidx = getOidx(c1idx) | var oidx = getOidx(c1idx) | ||
select {atomIndex=oidx} | select {atomIndex=oidx} | ||
| Line 947: | Line 976: | ||
else if (({atomIndex=targetIdx}.atomName == "N") | else if (({atomIndex=targetIdx}.atomName == "N") | ||
and ({atomIndex=targetIdx}.group != "GLY")) { | and ({atomIndex=targetIdx}.group != "GLY")) { | ||
| − | + | ||
| − | # Desired target location is r-tetragonal CB | + | # Desired target location is r-tetragonal CB |
var cbidx = getCBidx(c1idx) | var cbidx = getCBidx(c1idx) | ||
pt = getTet(cbidx, c1idx, c2idx, 1.5) | pt = getTet(cbidx, c1idx, c2idx, 1.5) | ||
} | } | ||
else { # C | else { # C | ||
| − | + | ||
# Save current target coords | # Save current target coords | ||
var cp = {atomIndex=targetIdx}.xyz | var cp = {atomIndex=targetIdx}.xyz | ||
| − | + | ||
# Set target atom at desired distance and angle | # Set target atom at desired distance and angle | ||
select {atomIndex=targetIdx} | select {atomIndex=targetIdx} | ||
setDistanceIdx(c1idx, targetIdx, 1.37) | setDistanceIdx(c1idx, targetIdx, 1.37) | ||
setAngleIdx(c2idx, c1idx, targetIdx, 110.0) | setAngleIdx(c2idx, c1idx, targetIdx, 110.0) | ||
| − | + | ||
if ({atomIndex=targetIdx}.group == "PRO") { | if ({atomIndex=targetIdx}.group == "PRO") { | ||
setDihedralIdx(c3idx, c2idx, c1idx, targetIdx, -57.0) | setDihedralIdx(c3idx, c2idx, c1idx, targetIdx, -57.0) | ||
} | } | ||
| − | + | ||
# Record and restore target | # Record and restore target | ||
pt = {atomIndex=targetIdx}.xyz | pt = {atomIndex=targetIdx}.xyz | ||
{atomIndex=targetIdx}.xyz = cp | {atomIndex=targetIdx}.xyz = cp | ||
} | } | ||
| − | + | ||
| − | # If target not at desired location | + | # If target not at desired location |
if (distance(pt, {atomIndex=targetIdx}) > kDtolerance) { | if (distance(pt, {atomIndex=targetIdx}) > kDtolerance) { | ||
var okCount = 0 | var okCount = 0 | ||
| Line 978: | Line 1,007: | ||
gOK = FALSE | gOK = FALSE | ||
while ((xcount < 20) and (gOK == FALSE)) { | while ((xcount < 20) and (gOK == FALSE)) { | ||
| − | + | ||
# Rotate on cWard rotor set to move it there | # Rotate on cWard rotor set to move it there | ||
tugTrackIdx(targetIdx, pt, TRUE, FALSE) | tugTrackIdx(targetIdx, pt, TRUE, FALSE) | ||
| Line 988: | Line 1,017: | ||
gOK = TRUE | gOK = TRUE | ||
okCount++ | okCount++ | ||
| − | } | + | } |
# If sucessful | # If sucessful | ||
if (gOK == TRUE) { | if (gOK == TRUE) { | ||
| − | + | ||
# Adust any side atoms | # Adust any side atoms | ||
| − | + | repairSideChain(targetIdx, TRUE) | |
} | } | ||
| − | + | ||
# Else fail | # Else fail | ||
else { | else { | ||
break | break | ||
} | } | ||
| − | + | ||
# If no movement in 4 tries, we are done | # If no movement in 4 tries, we are done | ||
if (okCount > 3) { | if (okCount > 3) { | ||
break | break | ||
} | } | ||
| − | + | ||
} # endwhile (targetIdx != gNanchorIdx) { | } # endwhile (targetIdx != gNanchorIdx) { | ||
| Line 1,040: | Line 1,069: | ||
} | } | ||
| − | function collectSCrotors(no) { | + | function collectSCrotors(no, iChain) { |
var scBondIdxs = array() | var scBondIdxs = array() | ||
for (var iNo = no; iNo >= 0; iNo--) { | for (var iNo = no; iNo >= 0; iNo--) { | ||
var ile = 0 | var ile = 0 | ||
| − | switch ({(atomno=iNo) and (chain= | + | switch ({(atomno=iNo) and (chain=iChain)}.atomName) { |
case "CA" : | case "CA" : | ||
return scBondIdxs # Early exit since break 1 appears broken | return scBondIdxs # Early exit since break 1 appears broken | ||
| − | |||
case "CZ" : | case "CZ" : | ||
| − | if ({(atomno=iNo) and (chain= | + | if ({(atomno=iNo) and (chain=iChain)}.group == "TYR") { |
break | break | ||
} | } | ||
case "CE" : | case "CE" : | ||
| − | if ({(atomno=iNo) and (chain= | + | if ({(atomno=iNo) and (chain=iChain)}.group == "MET") { |
break | break | ||
} | } | ||
case "CG1" : | case "CG1" : | ||
| − | if ({(atomno=iNo) and (chain= | + | if ({(atomno=iNo) and (chain=iChain)}.group == "VAL") { |
break | break | ||
} | } | ||
| − | if ({(atomno=iNo) and (chain= | + | if ({(atomno=iNo) and (chain=iChain)}.group == "ILE") { |
ile = 1 | ile = 1 | ||
} | } | ||
| Line 1,068: | Line 1,096: | ||
case "CG" : | case "CG" : | ||
case "CB" : | case "CB" : | ||
| − | scBondIdxs += {(atomno=@{iNo+1+ile}) and (chain= | + | scBondIdxs += {(atomno=@{iNo+1+ile}) and (chain=iChain)}.atomIndex |
| − | scBondIdxs += {(atomno=@{iNo+0}) and (chain= | + | scBondIdxs += {(atomno=@{iNo+0}) and (chain=iChain)}.atomIndex |
| − | if ({(atomno=iNo) and (chain= | + | if ({(atomno=iNo) and (chain=iChain)}.atomName%2 == "CG") { |
| − | scBondIdxs += {(atomno=@{iNo-1}) and (chain= | + | scBondIdxs += {(atomno=@{iNo-1}) and (chain=iChain)}.atomIndex |
| − | scBondIdxs += {(atomno=@{iNo-4}) and (chain= | + | scBondIdxs += {(atomno=@{iNo-4}) and (chain=iChain)}.atomIndex |
} | } | ||
| − | else if ({(atomno=iNo) and (chain= | + | else if ({(atomno=iNo) and (chain=iChain)}.atomName == "CB") { |
| − | scBondIdxs += {(atomno=@{iNo-3}) and (chain= | + | scBondIdxs += {(atomno=@{iNo-3}) and (chain=iChain)}.atomIndex |
| − | scBondIdxs += {(atomno=@{iNo-4}) and (chain= | + | scBondIdxs += {(atomno=@{iNo-4}) and (chain=iChain)}.atomIndex |
} | } | ||
else { | else { | ||
| − | scBondIdxs += {(atomno=@{iNo-1}) and (chain= | + | scBondIdxs += {(atomno=@{iNo-1}) and (chain=iChain)}.atomIndex |
| − | scBondIdxs += {(atomno=@{iNo-2}) and (chain= | + | scBondIdxs += {(atomno=@{iNo-2}) and (chain=iChain)}.atomIndex |
} | } | ||
break | break | ||
} | } | ||
| − | + | ||
} | } | ||
| − | + | ||
| − | return scBondIdxs | + | return scBondIdxs |
} | } | ||
| Line 1,094: | Line 1,122: | ||
var iNo = {atomIndex=gSCidx}.atomno | var iNo = {atomIndex=gSCidx}.atomno | ||
| − | + | var iChain = {atomIndex=gSCidx}.chain | |
| + | |||
if ({atomIndex=gSCidx}.group != "PRO") { | if ({atomIndex=gSCidx}.group != "PRO") { | ||
| − | + | ||
| − | var scBondIdxs = collectSCrotors( iNo) | + | var scBondIdxs = collectSCrotors( iNo, iChain) |
var numChi = scBondIdxs.size / 4 | var numChi = scBondIdxs.size / 4 | ||
var dist = distance({atomIndex=gSCidx}.xyz, gSCpt) | var dist = distance({atomIndex=gSCidx}.xyz, gSCpt) | ||
| + | |||
# For all rotor combinations | # For all rotor combinations | ||
var dh = array() | var dh = array() | ||
| Line 1,116: | Line 1,146: | ||
scBondIdxs[2+(4*i)], scBondIdxs[1+(4*i)], rot) | scBondIdxs[2+(4*i)], scBondIdxs[1+(4*i)], rot) | ||
var newDist = distance({atomIndex=gSCidx}.xyz, gSCpt) | var newDist = distance({atomIndex=gSCidx}.xyz, gSCpt) | ||
| − | + | ||
# Find the best | # Find the best | ||
if (newDist < dist) { | if (newDist < dist) { | ||
| Line 1,129: | Line 1,159: | ||
} | } | ||
} | } | ||
| − | + | ||
# Now set the best | # Now set the best | ||
for (var i = 0; i < numChi; i++) { | for (var i = 0; i < numChi; i++) { | ||
| Line 1,138: | Line 1,168: | ||
} | } | ||
else { # PRO - toggle between puckers up and down | else { # PRO - toggle between puckers up and down | ||
| − | var icd = {(atomno=@{iNo+1}) and (chain= | + | var icd = {(atomno=@{iNo+1}) and (chain=iChain)}.atomIndex |
| − | var icb = {(atomno=@{iNo-1}) and (chain= | + | var icb = {(atomno=@{iNo-1}) and (chain=iChain)}.atomIndex |
| − | var ica = {(atomno=@{iNo-4}) and (chain= | + | var ica = {(atomno=@{iNo-4}) and (chain=iChain)}.atomIndex |
| − | var in = {(atomno=@{iNo-5}) and (chain= | + | var in = {(atomno=@{iNo-5}) and (chain=iChain)}.atomIndex |
select {atomIndex=gSCidx} | select {atomIndex=gSCidx} | ||
| − | + | ||
if (angle({atomIndex=ica}, {atomIndex=in}, | if (angle({atomIndex=ica}, {atomIndex=in}, | ||
{atomIndex=icd}, {atomIndex=gSCidx}) < -10.0) { | {atomIndex=icd}, {atomIndex=gSCidx}) < -10.0) { | ||
| Line 1,156: | Line 1,186: | ||
} | } | ||
} | } | ||
| − | + | ||
draw gSCcircle CIRCLE {atomIndex=gSCidx} MESH NOFILL | draw gSCcircle CIRCLE {atomIndex=gSCidx} MESH NOFILL | ||
gSCpt = {atomIndex=gSCidx}.xyz | gSCpt = {atomIndex=gSCidx}.xyz | ||
} | } | ||
| − | + | ||
# Fix side chain collisions | # Fix side chain collisions | ||
function fixSCcollision2(idx) { | function fixSCcollision2(idx) { | ||
gOk2 = FALSE | gOk2 = FALSE | ||
var iNo = {atomIndex=idx}.atomno | var iNo = {atomIndex=idx}.atomno | ||
| − | var resno = {(atomno=iNo) and (chain= | + | var iChain = {atomIndex=idx}.chain |
| − | + | var resno = {(atomno=iNo) and (chain=iChain)}.resno | |
| + | |||
# Get SC terminus | # Get SC terminus | ||
| − | while (resno == {(atomno=iNo) and (chain= | + | while (resno == {(atomno=iNo) and (chain=iChain)}.resno) { |
iNo++ | iNo++ | ||
} | } | ||
iNo-- | iNo-- | ||
| − | + | ||
var sc = array() | var sc = array() | ||
var iBno = iNo | var iBno = iNo | ||
| − | while ({(atomno=iBno) and (chain= | + | while ({(atomno=iBno) and (chain=iChain)}.atomName != "CB") { |
| − | sc += {(atomno=iBno) and (chain= | + | sc += {(atomno=iBno) and (chain=iChain)} |
iBno-- | iBno-- | ||
} | } | ||
| − | var cbidx = {(atomno=iBno) and (chain= | + | var cbidx = {(atomno=iBno) and (chain=iChain)}.atomIndex |
| − | + | ||
| − | var scBondIdxs = collectSCrotors( iNo) | + | var scBondIdxs = collectSCrotors( iNo, iChain) |
var numChi = scBondIdxs.size / 4 | var numChi = scBondIdxs.size / 4 | ||
| + | |||
# For all rotor combinations | # For all rotor combinations | ||
for (var i = 0; i < numChi; i++) { | for (var i = 0; i < numChi; i++) { | ||
| Line 1,189: | Line 1,221: | ||
rot += 60 | rot += 60 | ||
selectAddSideChain(scBondIdxs[1+(4*i)]) | selectAddSideChain(scBondIdxs[1+(4*i)]) | ||
| − | |||
| − | |||
setDihedralIdx(scBondIdxs[1+(4*i)], scBondIdxs[2+(4*i)], | setDihedralIdx(scBondIdxs[1+(4*i)], scBondIdxs[2+(4*i)], | ||
scBondIdxs[3+(4*i)], scBondIdxs[4+(4*i)], rot) | scBondIdxs[3+(4*i)], scBondIdxs[4+(4*i)], rot) | ||
| + | |||
# If no collision, exit | # If no collision, exit | ||
colliders = (within(kCtolerance, FALSE, {sc}) | colliders = (within(kCtolerance, FALSE, {sc}) | ||
and not {atomIndex=cbidx} and not {sc}) | and not {atomIndex=cbidx} and not {sc}) | ||
| − | + | ||
# If it is with water, delete the water | # If it is with water, delete the water | ||
for (var c = 1; c < colliders.size; c++ ) { | for (var c = 1; c < colliders.size; c++ ) { | ||
| Line 1,204: | Line 1,235: | ||
} | } | ||
} | } | ||
| − | + | ||
if (colliders.size == 0) { | if (colliders.size == 0) { | ||
gOk2 = TRUE | gOk2 = TRUE | ||
return # Early exit since break 1 appears broken | return # Early exit since break 1 appears broken | ||
| − | |||
} | } | ||
| − | + | ||
} | } | ||
} | } | ||
| Line 1,248: | Line 1,278: | ||
var rotors = array() | var rotors = array() | ||
if (cargoNo < anchorNo) { | if (cargoNo < anchorNo) { | ||
| − | + | ||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
for (var iNo = cargoNo; iNo <= anchorNo; iNo++) { | for (var iNo = cargoNo; iNo <= anchorNo; iNo++) { | ||
if ({(atomno=iNo) and (chain=gChain)}.atomName == "CA") { | if ({(atomno=iNo) and (chain=gChain)}.atomName == "CA") { | ||
| Line 1,274: | Line 1,299: | ||
} | } | ||
else { | else { | ||
| − | + | ||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
for (var iNo = cargoNo; iNo >= anchorNo; iNo--) { | for (var iNo = cargoNo; iNo >= anchorNo; iNo--) { | ||
if ({(atomno=iNo) and (chain=gChain)}.atomName == "CA") { | if ({(atomno=iNo) and (chain=gChain)}.atomName == "CA") { | ||
| Line 1,299: | Line 1,319: | ||
} | } | ||
} | } | ||
| − | + | ||
if (nWard) { | if (nWard) { | ||
gNrotors = rotors | gNrotors = rotors | ||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
} | } | ||
else { | else { | ||
gCrotors = rotors | gCrotors = rotors | ||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
} | } | ||
} | } | ||
| Line 1,332: | Line 1,334: | ||
function tugSideChain(pt) { | function tugSideChain(pt) { | ||
| − | + | ||
# If destination atom defined | # If destination atom defined | ||
if (gDestAtomIdx >= 0) { | if (gDestAtomIdx >= 0) { | ||
| − | v = {atomIndex=gDestAtomIdx}.xyz - {atomIndex=gSCidx}.xyz | + | var v = {atomIndex=gDestAtomIdx}.xyz - {atomIndex=gSCidx}.xyz |
if (abs(angle({atomIndex=gDestAtomIdx}.xyz, {0 0 0}, pt)) < 90) { | if (abs(angle({atomIndex=gDestAtomIdx}.xyz, {0 0 0}, pt)) < 90) { | ||
pt = -v/20.0 | pt = -v/20.0 | ||
| Line 1,344: | Line 1,346: | ||
} | } | ||
gSCpt += pt | gSCpt += pt | ||
| − | draw arrow {atomIndex=gSCidx} @gSCpt | + | draw arrow {atomIndex=gSCidx} @gSCpt |
} | } | ||
| Line 1,350: | Line 1,352: | ||
select all | select all | ||
color {selected} @gScheme | color {selected} @gScheme | ||
| − | |||
| − | |||
color {atomIndex=g1pivotIdx} green | color {atomIndex=g1pivotIdx} green | ||
color {atomIndex=g2pivotIdx} green | color {atomIndex=g2pivotIdx} green | ||
| − | color @ | + | color @gCargoSet @gAltScheme |
| − | select {(atomIndex=gCcargoIdx) or (atomIndex=gNcargoIdx)} | + | select {(atomIndex=gCcargoIdx) or (atomIndex=gNcargoIdx) |
| + | or (atomIndex=gCanchorIdx) or (atomIndex=gNanchorIdx)} | ||
halo on | halo on | ||
select {atomIndex=gDestAtomIdx} | select {atomIndex=gDestAtomIdx} | ||
| Line 1,379: | Line 1,380: | ||
background ECHO yellow | background ECHO yellow | ||
restore state gState | restore state gState | ||
| − | select | + | select gCargoSet |
refresh | refresh | ||
quit | quit | ||
| Line 1,390: | Line 1,391: | ||
ls += format("gNanchorIdx = %d;", gNanchorIdx) | ls += format("gNanchorIdx = %d;", gNanchorIdx) | ||
ls += format("gNanchorNo = %d;", gNanchorNo) | ls += format("gNanchorNo = %d;", gNanchorNo) | ||
| − | |||
| − | |||
| − | |||
| − | |||
ls += format("gCcargoIdx = %d;", gCcargoIdx) | ls += format("gCcargoIdx = %d;", gCcargoIdx) | ||
ls += format("gNcargoIdx = %d;", gNcargoIdx) | ls += format("gNcargoIdx = %d;", gNcargoIdx) | ||
| − | |||
| − | |||
ls += format("gCcargoNo = %d;", gCcargoNo) | ls += format("gCcargoNo = %d;", gCcargoNo) | ||
ls += format("gNcargoNo = %d;", gNcargoNo) | ls += format("gNcargoNo = %d;", gNcargoNo) | ||
| Line 1,403: | Line 1,398: | ||
ls += format("g1pivotIdx = %d;", g1pivotIdx) | ls += format("g1pivotIdx = %d;", g1pivotIdx) | ||
ls += format("g2pivotIdx = %d;", g2pivotIdx) | ls += format("g2pivotIdx = %d;", g2pivotIdx) | ||
| − | ls += format(" | + | ls += format("gOkCollide = %s;", gOkCollide) |
ls += format("gChain = \"%s\";", gChain) | ls += format("gChain = \"%s\";", gChain) | ||
ls += format("gMinNo = %d;", gMinNo) | ls += format("gMinNo = %d;", gMinNo) | ||
| − | ls += format("gMaxNo = %d;", gMaxNo) | + | ls += format("gMaxNo = %d;", gMaxNo) |
| − | ls += format(" | + | ls += format("gCargoSet = %s;", gCargoSet) |
ls += format("gSCidx = %d;", gSCidx) | ls += format("gSCidx = %d;", gSCidx) | ||
ls += format("gSCcircle = %d;", gSCcircle) | ls += format("gSCcircle = %d;", gSCcircle) | ||
| Line 1,418: | Line 1,413: | ||
# Bound to LEFT-UP by tugEnableDrag | # Bound to LEFT-UP by tugEnableDrag | ||
function tugDragDoneMB() { | function tugDragDoneMB() { | ||
| − | if (gPlicoRecord != "") { | + | if (gBusy == FALSE) { |
| − | + | 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 | |
| − | + | 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 ( | ||
| − | |||
| − | |||
| − | if ( | ||
| − | |||
| − | |||
| − | |||
} | } | ||
| − | + | if (gOK and (gNrotors.size > 4)) { | |
| − | + | tugTrackN() # PULLSTRING MODEL | |
| − | |||
| − | |||
| − | if (( | ||
| − | |||
| − | |||
| − | |||
} | } | ||
} | } | ||
| − | + | 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}.atomno.min}) | ||
| + | and (chain=gChain)}.atomIndex | ||
| − | |||
| − | |||
| − | |||
| − | + | var ihc = 0 | |
| − | + | for (ihc = 0; ihc < 10; ihc++) { | |
| − | + | handleCollisions2(FALSE, 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 | # Bound to ALT-LEFT-DRAG by tugEnableDrag | ||
| − | function tugDragMB() { | + | function tugDragMB(alt) { |
if (gBusy == FALSE) { | if (gBusy == FALSE) { | ||
| − | var dx = ( | + | gBusy = TRUE |
| − | var dy = ( | + | var dx = (40.0 * (_mouseX - gMouseX))/_width |
| − | var q = quaternion( | + | var dy = (40.0 * (_mouseY - gMouseY))/_height |
| + | var q = quaternion() | ||
var ptd = {@dx @dy 0} | var ptd = {@dx @dy 0} | ||
var pt = (!q)%ptd | var pt = (!q)%ptd | ||
| − | + | var axis = {0 0 0} | |
if (distance(pt, {0 0 0}) > 0.004) { | if (distance(pt, {0 0 0}) > 0.004) { | ||
| − | |||
# If sidechain mode | # If sidechain mode | ||
if (gSCidx >= 0) { | if (gSCidx >= 0) { | ||
| − | tugSideChain(pt) | + | if ({atomIndex=gSCidx}.atomName == "O") { |
| + | dir = ((abs(dx) > abs(dy)) | ||
| + | ? ((dx < 0) ? 2 : -2) | ||
| + | : ((dy < 0) ? 2 : -2)) | ||
| + | counterRotate(gSCidx, dir, not alt) | ||
| + | } | ||
| + | else { | ||
| + | tugSideChain(pt) | ||
| + | } | ||
} | } | ||
| − | # Else | + | # Else |
else { | else { | ||
| − | + | ||
# If new drag | # If new drag | ||
if (gNewDrag) { | if (gNewDrag) { | ||
| Line 1,533: | Line 1,543: | ||
save state gState | save state gState | ||
} | } | ||
| − | + | ||
| − | |||
| − | |||
# If destination atom defined | # If destination atom defined | ||
if (gDestAtomIdx >= 0) { | if (gDestAtomIdx >= 0) { | ||
| Line 1,546: | Line 1,554: | ||
} | } | ||
} | } | ||
| − | + | ||
# Move the cargo | # Move the cargo | ||
| − | select { | + | select {gCargoSet} |
| − | + | ||
# If pivots defined, rotate it | # If pivots defined, rotate it | ||
if (g1pivotIdx >= 0) { | if (g1pivotIdx >= 0) { | ||
| − | + | ||
# If two pivots | # If two pivots | ||
| − | |||
if (g2pivotIdx >= 0) { | if (g2pivotIdx >= 0) { | ||
axis = {atomIndex=g2pivotIdx} | axis = {atomIndex=g2pivotIdx} | ||
} | } | ||
| − | + | ||
# Else | # Else | ||
else { | else { | ||
axis = cross(pt, {0 0 0}) + {atomIndex=g1pivotIdx}.xyz | 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, | + | rotateSelectedRecord(g1pivotIdx, axis, dir) |
| − | + | ||
} | } | ||
| − | + | ||
# Else translate it | # Else translate it | ||
else { | else { | ||
| − | |||
translateSelectedRecord(pt) | translateSelectedRecord(pt) | ||
} | } | ||
| − | + | ||
# If collisions | # If collisions | ||
| − | var | + | var cNotSels = (within(kCtolerance, FALSE, {selected}) |
| − | + | and not {gMovingSet}) | |
| − | + | if (cNotSels.size > 0) { | |
| − | + | gOk2 = TRUE | |
| − | if ( | + | for (var i = 1; i <= cNotSels.size; i++) { |
| − | + | ||
| − | for (var i = 1; i <= | + | # If net collision vector same as move vector |
| − | select | + | 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 unable | + | |
| − | if (gOk2 == FALSE) { | + | # If tow mode |
| − | + | if (gTow) { | |
| − | # Back off | + | |
| − | background ECHO pink | + | # 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(FALSE, idx) | ||
| + | } | ||
| + | } | ||
| + | } # endfor | ||
| + | if (gOk2 == FALSE) { | ||
| + | break | ||
| + | } | ||
| + | } # endfor | ||
| + | |||
| + | # If unable and not alt | ||
| + | if ((gOk2 == FALSE) and (not alt)) { | ||
| + | |||
| + | # Back off | ||
| + | background ECHO pink | ||
delay 1 | delay 1 | ||
if (g1pivotIdx >= 0) { | if (g1pivotIdx >= 0) { | ||
| Line 1,604: | Line 1,650: | ||
} | } | ||
} | } | ||
| − | |||
} | } | ||
| − | + | ||
| + | # 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 | gMouseX = _mouseX | ||
gMouseY = _mouseY | gMouseY = _mouseY | ||
} | } | ||
| − | select { | + | select {gCargoSet} |
| + | gBusy = FALSE | ||
} | } | ||
} | } | ||
| Line 1,618: | Line 1,683: | ||
gMouseX = _mouseX | gMouseX = _mouseX | ||
gMouseY = _mouseY | gMouseY = _mouseY | ||
| − | |||
| − | |||
gNewDrag = TRUE | gNewDrag = TRUE | ||
} | } | ||
| − | # Called by tugCargoMB | + | # Called by tugCargoMB |
function tugEnableDrag() { | function tugEnableDrag() { | ||
| − | gEcho = "ALT-CLICK= | + | 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 | echo @gEcho | ||
| − | + | ||
# Allow atoms to be dragged | # Allow atoms to be dragged | ||
bind "ALT-LEFT-DOWN" "tugMarkMB"; | bind "ALT-LEFT-DOWN" "tugMarkMB"; | ||
| − | bind "ALT-LEFT-UP" "tugDragDoneMB"; | + | bind "ALT-LEFT-UP" "tugDragDoneMB"; |
bind "ALT-LEFT-DRAG" "tugDragMB"; | 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"; | ||
| − | # Bound to SHIFT-LEFT-CLICK by tugCargoMB | + | bind "ALT-CTRL-LEFT-CLICK" "_pickAtom"; |
| − | function tugAnchorMB() { | + | bind "ALT-CTRL-LEFT-CLICK" "+:tugPivotMB"; |
| − | if ({atomIndex=_atomPicked}.chain == gChain) { | + | |
| + | 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) | var aPidx = getScBBidx( _atomPicked) | ||
| − | + | ||
var pno = {atomIndex=aPidx}.atomno | var pno = {atomIndex=aPidx}.atomno | ||
if (pno > {atomIndex=gCcargoIdx}.atomno) { | if (pno > {atomIndex=gCcargoIdx}.atomno) { | ||
| − | + | select {atomIndex=gCanchorIdx} | |
| + | halo off | ||
if (gCanchorIdx == aPidx) { | if (gCanchorIdx == aPidx) { | ||
gCanchorIdx = -1 | gCanchorIdx = -1 | ||
| Line 1,649: | Line 1,726: | ||
gCanchorIdx = aPidx | gCanchorIdx = aPidx | ||
gCanchorNo = {atomIndex=gCanchorIdx}.atomno | gCanchorNo = {atomIndex=gCanchorIdx}.atomno | ||
| − | + | select {atomIndex=gCanchorIdx} | |
| − | + | halo on | |
} | } | ||
collectBBrotors(FALSE) | collectBBrotors(FALSE) | ||
} | } | ||
| − | if (pno < {atomIndex=gNcargoIdx}.atomno) { | + | else if (pno < {atomIndex=gNcargoIdx}.atomno) { |
| − | + | select {atomIndex=gNanchorIdx} | |
| + | halo off | ||
if (gNanchorIdx == aPidx) { | if (gNanchorIdx == aPidx) { | ||
gNanchorIdx = -1 | gNanchorIdx = -1 | ||
| Line 1,663: | Line 1,741: | ||
gNanchorIdx = aPidx | gNanchorIdx = aPidx | ||
gNanchorNo = {atomIndex=gNanchorIdx}.atomno | gNanchorNo = {atomIndex=gNanchorIdx}.atomno | ||
| − | + | select {atomIndex=gNanchorIdx} | |
| − | + | halo on | |
| − | |||
| − | |||
} | } | ||
collectBBrotors(TRUE) | collectBBrotors(TRUE) | ||
} | } | ||
| + | else { | ||
| + | towCargoMB() | ||
| + | } | ||
| + | |||
| + | # Get moving atoms set | ||
| + | gMovingSet = {((atomno < gCanchorNo) and (atomno > gNanchorNo) | ||
| + | and (chain=gChain))} | ||
} | } | ||
| − | + | select {gCargoSet} | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | select { | ||
} | } | ||
| Line 1,700: | Line 1,778: | ||
star on | star on | ||
} | } | ||
| − | select { | + | select {gCargoSet} |
} | } | ||
} | } | ||
| Line 1,724: | Line 1,802: | ||
color {atomIndex=g2pivotIdx} @gScheme | color {atomIndex=g2pivotIdx} @gScheme | ||
} | } | ||
| − | + | ||
g2pivotIdx = _atomPicked | g2pivotIdx = _atomPicked | ||
color {atomIndex=g2pivotIdx} green | color {atomIndex=g2pivotIdx} green | ||
| Line 1,732: | Line 1,810: | ||
color {atomIndex=g1pivotIdx} green | color {atomIndex=g1pivotIdx} green | ||
} | } | ||
| − | select { | + | 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 | # Bound to ALT-LEFT-CLICK by plicoTug | ||
function tugCargoMB() { | function tugCargoMB() { | ||
| − | + | ||
| − | if ( | + | # If O or movable side chain atom picked |
| − | + | if (({atomIndex=_atomPicked}.atomName = "O") | |
| − | + | or (isMovableSideChain( _atomPicked))) { | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
if (gSCidx >= 0) { | if (gSCidx >= 0) { | ||
draw gSCcircle DELETE | draw gSCcircle DELETE | ||
| Line 1,751: | Line 1,854: | ||
if (gSCidx == _atomPicked) { | if (gSCidx == _atomPicked) { | ||
gSCidx = -1 | gSCidx = -1 | ||
| − | } | + | } |
else { | else { | ||
gSCidx = _atomPicked | gSCidx = _atomPicked | ||
| Line 1,758: | Line 1,861: | ||
} | } | ||
} | } | ||
| − | else if ( | + | else { |
| − | gMinNo = {chain=gChain}.atomno.min | + | 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 | gMaxNo = {chain=gChain}.atomno.max | ||
if (gNanchorIdx < 0) { | if (gNanchorIdx < 0) { | ||
| Line 1,765: | Line 1,883: | ||
} | } | ||
if (gCanchorIdx < 0) { | if (gCanchorIdx < 0) { | ||
| − | gCanchorNo = gMaxNo + 1 | + | gCanchorNo = gMaxNo + 1 |
} | } | ||
var aPidx = getScBBidx( _atomPicked) | var aPidx = getScBBidx( _atomPicked) | ||
| − | + | ||
gSCidx = -1 | gSCidx = -1 | ||
draw gSCcircle DELETE | draw gSCcircle DELETE | ||
| Line 1,774: | Line 1,892: | ||
# If existing cWard cargo picked | # If existing cWard cargo picked | ||
if (gCcargoIdx == aPidx) { | if (gCcargoIdx == aPidx) { | ||
| − | + | ||
# Clear the highlight | # Clear the highlight | ||
select {atomIndex=gCcargoIdx} | select {atomIndex=gCcargoIdx} | ||
halo off | halo off | ||
| − | + | ||
# If nWard cargo exists, mark it as the cWard cargo | # If nWard cargo exists, mark it as the cWard cargo | ||
if (gNcargoIdx != gCcargoIdx) { | if (gNcargoIdx != gCcargoIdx) { | ||
| Line 1,796: | Line 1,914: | ||
} | } | ||
else if (gCcargoIdx >= 0) { | else if (gCcargoIdx >= 0) { | ||
| + | |||
var no = {atomIndex=aPidx}.atomno | var no = {atomIndex=aPidx}.atomno | ||
| − | + | ||
# If pick is nWard of it | # If pick is nWard of it | ||
if (no < {atomIndex=gCcargoIdx}.atomno) { | if (no < {atomIndex=gCcargoIdx}.atomno) { | ||
| − | + | ||
# If exists, clear its highlight | # If exists, clear its highlight | ||
if (gNcargoIdx != gCcargoIdx) { | if (gNcargoIdx != gCcargoIdx) { | ||
| Line 1,806: | Line 1,925: | ||
halo off | halo off | ||
} | } | ||
| − | + | ||
# Set new nWard cargo and highlight it | # Set new nWard cargo and highlight it | ||
gNcargoIdx = getNmIdx(aPidx) | gNcargoIdx = getNmIdx(aPidx) | ||
gNcargoNo = {atomIndex=gNcargoIdx}.atomno | gNcargoNo = {atomIndex=gNcargoIdx}.atomno | ||
} | } | ||
| − | + | ||
# Else cWard | # Else cWard | ||
else { | else { | ||
| − | + | ||
# Clear its old highlight | # Clear its old highlight | ||
select {atomIndex=gCcargoIdx} | select {atomIndex=gCcargoIdx} | ||
| Line 1,820: | Line 1,939: | ||
halo off | halo off | ||
} | } | ||
| − | + | ||
# Set new cWard cargo and highlight | # Set new cWard cargo and highlight | ||
gCcargoIdx = getCpIdx(aPidx) | gCcargoIdx = getCpIdx(aPidx) | ||
| Line 1,826: | Line 1,945: | ||
} | } | ||
} | } | ||
| − | + | ||
# Else no cWard cargo | # Else no cWard cargo | ||
else { | else { | ||
| − | + | ||
# Set new cWard cargo and highlight | # Set new cWard cargo and highlight | ||
gCcargoIdx = getCpIdx(aPidx) | gCcargoIdx = getCpIdx(aPidx) | ||
| Line 1,835: | Line 1,954: | ||
gNcargoIdx = getNmIdx(gCcargoIdx) | gNcargoIdx = getNmIdx(gCcargoIdx) | ||
gNcargoNo = {atomIndex=gNcargoIdx}.atomno | gNcargoNo = {atomIndex=gNcargoIdx}.atomno | ||
| − | + | ||
# Set default cWard anchor at cWard N | # Set default cWard anchor at cWard N | ||
var iNo = gMaxNo | var iNo = gMaxNo | ||
| Line 1,845: | Line 1,964: | ||
gCanchorIdx = {(atomno=iNo) and (chain=gChain)}.atomIndex | gCanchorIdx = {(atomno=iNo) and (chain=gChain)}.atomIndex | ||
gCanchorNo = {atomIndex=gCanchorIdx}.atomno | gCanchorNo = {atomIndex=gCanchorIdx}.atomno | ||
| − | |||
} | } | ||
| − | + | ||
# If any anchor now inside cargo cluster, kill it | # If any anchor now inside cargo cluster, kill it | ||
if ({atomIndex=gCanchorIdx}.atomno <= {atomIndex=gCcargoIdx}.atomno) { | if ({atomIndex=gCanchorIdx}.atomno <= {atomIndex=gCcargoIdx}.atomno) { | ||
| Line 1,857: | Line 1,975: | ||
gNanchorNo = gMinNo - 1 | gNanchorNo = gMinNo - 1 | ||
} | } | ||
| − | + | ||
# Highlight cargo cluster | # Highlight cargo cluster | ||
| − | + | selectNwardIdx(gCcargoIdx, gNcargoIdx) | |
| − | + | gCargoSet = {selected} | |
setColors() | setColors() | ||
| − | + | ||
# Collect the rotor sets | # Collect the rotor sets | ||
collectRotors() | collectRotors() | ||
| − | + | ||
| − | # Get | + | # Get moving atoms set |
| − | + | gMovingSet = {((atomno < gCanchorNo) and (atomno > gNanchorNo) | |
| − | and (chain=gChain))} | + | and (chain=gChain))} |
| − | |||
} | } | ||
| − | + | ||
# Enable dragging | # Enable dragging | ||
tugEnableDrag() | tugEnableDrag() | ||
| − | + | select {gCargoSet} | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | select { | ||
} | } | ||
# Top level of Tug | # Top level of Tug | ||
function plicoTug() { | function plicoTug() { | ||
| − | + | ||
| − | + | # Bad idea to proceed when collisions present | |
| − | + | var cc = countCollisions(({})) | |
| − | + | if (cc > 0) { | |
| + | var p = prompt(format("%d collision%s present! Proceed anyway?", | ||
| + | cc, ((cc > 1) ? "s" : "")), "OK|Cancel", TRUE) | ||
| + | if (p == "Cancel") { | ||
| + | quit | ||
| + | } | ||
| + | } | ||
| + | |||
# Push selected | # Push selected | ||
gSelSaves = {selected} | gSelSaves = {selected} | ||
| Line 1,901: | Line 2,015: | ||
write tugsave.pdb | write tugsave.pdb | ||
select none | select none | ||
| − | + | ||
gScheme = defaultColorScheme | gScheme = defaultColorScheme | ||
gAltScheme = ((gScheme == "Jmol") ? "Rasmol" : "Jmol") | gAltScheme = ((gScheme == "Jmol") ? "Rasmol" : "Jmol") | ||
set echo TOP LEFT | set echo TOP LEFT | ||
background ECHO yellow | background ECHO yellow | ||
| − | gEcho = "ALT-CLICK= | + | gEcho = ("_________TUG_________|ALT-CLICK=mark block|SHIFT-CLICK=mark chain" + |
| + | "|DOUBLE-CLICK=exit") | ||
echo @gEcho | echo @gEcho | ||
gCrotors = array() | gCrotors = array() | ||
| Line 1,914: | Line 2,029: | ||
unbind | unbind | ||
| − | |||
bind "ALT-LEFT-CLICK" "_pickAtom"; | bind "ALT-LEFT-CLICK" "_pickAtom"; | ||
bind "ALT-LEFT-CLICK" "+:tugCargoMB"; | bind "ALT-LEFT-CLICK" "+:tugCargoMB"; | ||
| + | bind "SHIFT-LEFT-CLICK" "_pickAtom"; | ||
| + | bind "SHIFT-LEFT-CLICK" "+:towCargoMB"; | ||
bind "DOUBLE" "tugExit"; | bind "DOUBLE" "tugExit"; | ||
} | } | ||
| Line 1,934: | Line 2,050: | ||
if (p != "No") { | if (p != "No") { | ||
unbind | unbind | ||
| − | halo off | + | halo off |
set allowMoveAtoms FALSE | set allowMoveAtoms FALSE | ||
echo | echo | ||
| Line 1,944: | Line 2,060: | ||
gBusy = FALSE | gBusy = FALSE | ||
background ECHO yellow | background ECHO yellow | ||
| − | + | ||
# Pop selected | # Pop selected | ||
select gSelSaves | select gSelSaves | ||
Revision as of 20:49, 12 February 2014
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.1 beta 2/12/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
# 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
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 = cAtom 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)}},
{atomIndex=idx} , {atomIndex=@{getNwardBBidx(idx)}}) < 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 (gOk2 == FALSE) {
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 (gOk2 == FALSE) {
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 (gOk2 == FALSE) {
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 (gOk2 == FALSE) {
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)}}, {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
selectNwardIdx(i3, getCwardBBidx(targetIdx))
{atomIndex=targetIdx}.selected = TRUE
}
else {
selectCwardIdx(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
selectCwardIdx(i3, getNwardBBidx(targetIdx))
{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( 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 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 selsave = {selected}
var iChain = {atomIndex=oIdx}.chain
var cIdx = getScBBidx(oIdx)
var nIdx = getCwardBBidx(cIdx)
var caPhiIdx = getCwardBBidx(nIdx)
var caPsiIdx = getNwardBBidx(cIdx)
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 selsave = {selected}
var gOk2 = TRUE
var cIdx = getScBBidx(oIdx)
var nIdx = getCwardBBidx(cIdx)
var caPhiIdx = getCwardBBidx(nIdx)
var caPsiIdx = getNwardBBidx(cIdx)
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) : 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(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)
# 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, 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 (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
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)
# 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
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)
# 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=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
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 (gBusy == FALSE) {
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)
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}.atomno.min})
and (chain=gChain)}.atomIndex
var ihc = 0
for (ihc = 0; ihc < 10; ihc++) {
handleCollisions2(FALSE, 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 (gBusy == FALSE) {
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 {
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) {
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(FALSE, idx)
}
}
} # endfor
if (gOk2 == FALSE) {
break
}
} # endfor
# If unable and not alt
if ((gOk2 == FALSE) and (not alt)) {
# 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-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)
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
}
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 {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)
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() {
# Bad idea to proceed when collisions present
var cc = countCollisions(({}))
if (cc > 0) {
var p = prompt(format("%d collision%s present! Proceed anyway?",
cc, ((cc > 1) ? "s" : "")), "OK|Cancel", TRUE)
if (p == "Cancel") {
quit
}
}
# 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 = ("_________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