Icon representing a recipe

Recipe: Loop Turn-Twist 1.0

created by brow42

Profile


Name
Loop Turn-Twist 1.0
ID
39500
Shared with
Public
Parent
None
Children
None
Created on
July 18, 2012 at 19:52 PM UTC
Updated on
July 18, 2012 at 19:52 PM UTC
Description

Twists and Rotates segments. Like sheet rotation, but also twists, and works on loops and around U-turns. Experimental, doesn't always work. Maybe you can figure out why?

Best for


Code


--[[ * Loop Turn-Twist * Original Author: Brow42 Mar. 12 2012 * Version 0.1 beta May 30, 2012 (valid to July 15 2012) * This script will turn and/or twist a region of the protein. * Unlike the tweak tool, it work on loops, not just sheets, * and it can make a twist, not just straighten. A good use * is to continue the turn/twist around U-turns at the end of a sheet. * * The script has a built in undo function, so you can back * up if you turn/twist too far, or in the wrong direction. * * Unfortunately, it doesn't seem strong enough to actually do * turn/twist. This recipe is experimental. * Version 1.0 July 18 2012 Brow42 * removed beta notice --]] title = 'Loop Turner-Twister 1.0' rangestr = "" -- initial range --beta_date = os.time({year=2012, month=7, day=15}) -- ================================== Begin New Dialog Library Functions --[[ Throws up a dialog containing just text, provided as a string or table of strings in the first argument. Title and buttons are optional. Return value is 1 if the first button is clicked and 0 if the second button is clicked or the window is closed. --]] function dialog.MessageBox(msg,title,buttontext1, buttontext0) title = title or '' local d = dialog.CreateDialog(title) if type(msg) == 'string' then d['1'] = dialog.AddLabel(msg) else for i = 1,#msg do d[tostring(i)] = dialog.AddLabel(msg[i]) end end buttontext1 = buttontext1 or 'Ok' d.button = dialog.AddButton(buttontext1,1) if buttontext0 then d.button0 = dialog.AddButton(buttontext0,0) end return dialog.Show(d) end -- ================================== End New Dialog Library Functions -- ========================== Begin Small AA Atom Database ================ fsl = fsl or {} -- make sure fsl namespace exists fsl.atom = {} -- Take just these 4 things if all you need is to know if the sidechain starts at 5 or 6 (tail terminal = true) fsl.atom.atomcount = { -- shorter table just for identifying terminals a=10, c=11, d=12, e=15, f=20, g=7, h=17, i=19, k=22, l=19, m=17, n=14, p=15, q=17, r=24, s=11, t=14, v=16, w=24, y=21 } -- Pass in a segment number of a cysteine function fsl.atom._IsDisulfideBonded(iSeg) local s = current.GetSegmentEnergySubscore(iSeg,'disulfides') return tostring(s) ~= '-0' end function fsl.atom._IsTerminalTest(aa,count,disulfide) local dbvalue = fsl.atom.atomcount[aa] if dbvalue == nil then error('Bad argument to an fsl.atom function (not an amino acid code)') end local diff = count - dbvalue if disulfide then diff = diff + 1 end -- because count is one less because a H was removed if diff == 0 then return false, false, disulfide elseif diff == 1 then return false, true, disulfide elseif diff == 2 then return true, false, disulfide elseif diff == 3 then return true, true, disulfide end error('Strange atom count, report this!') end -- Determine if segment is start or end of polypeptide by looking for excess atoms function fsl.atom.IsTerminal(iSeg) if structure.GetSecondaryStructure(iSeg) == 'M' then return false,false,false end local aa = structure.GetAminoAcid(iSeg) local count = structure.GetAtomCount(iSeg) return fsl.atom._IsTerminalTest(aa,count,fsl.atom._IsDisulfideBonded(iSeg)) end -- ========================== End Small AA Atom Database ================ -- ================================== Begin Undo -- Undo functionality undo = {} undo._NUndo = 25 -- 25 undo slots in the gui so max 25 undo._iSlot = 1 -- the next slot to be saved into 1 to NUndo undo._NSaved = 0 -- 0 to NUndo -- Get how many saved solutions there are function undo.GetCount() return undo._NSaved end -- Pushes current state onto circular undo buffer, returns buffer size function undo.Save() save.Quicksave(101 - undo._iSlot) undo._iSlot = 1 + undo._iSlot % undo._NUndo undo._NSaved = math.min(undo._NSaved + 1, undo._NUndo) return undo._NSaved end -- pops the top save from undo buffer, returns false if empty function undo.Undo() if undo._NSaved < 1 then error('No more saves in undo buffer') end undo._NSaved = undo._NSaved - 1 undo._iSlot = 1 + (undo._iSlot +undo._NUndo - 2) % undo._NUndo save.Quickload(101-undo._iSlot) return undo._NSaved > 0 end -- Pull the oldest save out (FIFO) function undo.PopTail() if undo._NSaved < 1 then error('No more saves in undo buffer') end local i = 1 + (undo._iSlot - 1 - undo._NSaved + undo._NUndo) % undo._NUndo save.Quickload(101-i) undo._NSaved = undo._NSaved - 1 return undo._NSaved > 0 end -- ================================== End Undo -- ================================== Begin Dialogs function About() local msg = { 'This rotates and twists loops and sheets.' , 'RIGHT means: pretend to wrap your right hand' , 'around a loop with the thumb pointing to the' , 'higher-number segement. Your fingers curl in' , 'RIGHT direction (+1). LEFT is the opposite (-1).' , 'Twist +1 mean extra RIGHT (or less LEFT) at' , 'end than at the start. -1 means the opposite.', 'Twist = Rotate means first segment wont\'t turn.', 'Twist = - Rotate means last won\'t turn', '', 'Repetitions - 1 or more turn/twist per click', 'Undo - back up 1 turn/twist', 'Atom - distance up the sidechain to band' } dialog.MessageBox(msg,'About '..title) end function MainDialog() local d = dialog.CreateDialog(title) if beta_date then d.beta = dialog.AddLabel(string.format( ' * This is a BETA recipe that expires %s.',os.date('%b. %d %Y',beta_date))) end d.label1 = dialog.AddLabel('Rotate loops with optional extra twist.') d.label2 = dialog.AddLabel('Imagine a rolled up towel in a U-shape...') d.label3 = dialog.AddLabel('1) Band to save shape 2) select in Selection') d.label4 = dialog.AddLabel('or in box 3) Set settings 4) Click Turn 5) Repeat') d.rotation = dialog.AddSlider('Rotate (band len):',0,-2,2,2) d.twist = dialog.AddSlider('Twist :',0,-2,2,2) d.str = dialog.AddSlider('Strength:',1,0.1,10,1) d.repeating = dialog.AddSlider('Repetitions:',1,1,10,0) d.nwiggle = dialog.AddSlider('# Wiggle per turn:',3,1,10,0) d.atom = dialog.AddSlider('Sidechain atom:',1,1,10,0) d.skip = dialog.AddSlider('Band every N segs:',1,1,5,0) d.start = dialog.AddButton('Turn Some',1) d.cancel = dialog.AddButton('Exit',0) d.about = dialog.AddButton('Help',2) d.undo = dialog.AddButton('Undo',3) d.range = dialog.AddTextbox('Range',rangestr) return d end -- returns a table of 2 numbers or nil function ParseRangeString(str) local r = {} for x in str:gfind('%d+') do r[#r+1]=tonumber(x) end if #r == 1 then return {r[1], r[1]} end if #r ~= 2 then return end if r[1] > r[2] then r[1],r[2] = r[2],r[1] end if r[1] < 1 or r[2] > structure.GetCount() then return end return r end -- ================================== End Dialogs -- ================================== Begin Work Functions -- Make a right-angle band -- If len is negative, reverse it function Band(iSeg, len, atom, str) local goal = 0.01 if structure.GetAminoAcid(iSeg) == 'g' then return end local n = structure.GetCount() local s2,s3 if iSeg == 1 then s2,s3 = 2,3 elseif iSeg == n then s2,s3,len = n-1,n-2,-len else s2,s3 = iSeg+1, iSeg-1 end local phi, theta = 0, math.pi/2 if len < 0 then phi,theta,len = phi + math.pi, theta, -len elseif len == 0 then len = goal end local iBand = band.Add(iSeg,s2,s3,len,phi,theta,atom) if iBand > 0 then band.SetStrength(iBand,str) band.SetGoalLength(iBand,goal) end end -- Band up segments in range rotating 'rot', -- adding a twist 'twist' on top of that, -- with band str 'str' on sidechain atom 'atom' -- and also a pinning band on the backbone C-alpha function DoIt(range,rot,twist,str,atom,skip) local s local n = range[2] - range[1] + 1 local m = (n-1)/2 if n == 1 then twist,m = 0, 1 end -- no twist if just 1 seg for i = 0,n-1,skip do j = i + range[1] s = rot + twist * (i-m)/m -- combined rotation and twist -- s = s * (i % 2 - 0.5) * 2 -- goofiness -- print (i,s) if structure.GetSecondaryStructure(j) ~= 'M' then -- no ligands local sc = 4 + atom if sc <= fsl.atom.atomcount[structure.GetAminoAcid(j)] then local first,last,disulfide = fsl.atom.IsTerminal(j) Band(j,s, sc + (first and 1 or 0),str) end end Band(j,0,0,str) -- pinning band end end -- ================================== End Work Functions -- ================================== Begin Main if beta_date and beta_date < os.time() then dialog.MessageBox({'This beta software has expired.','Please download a new copy today!'},'Recipe Update') end -- use initial selection if present if rangestr == "" then local list = {} for i = 1,structure.GetCount() do if selection.IsSelected(i) then list[#list+1] = i end end if #list > 0 then rangestr = string.format("%d %d",list[1],list[#list]) end end d = MainDialog() while true do d.undo.label = string.format("Undo (%d)",undo.GetCount()) local rc = dialog.Show(d) if rc == 0 then break elseif rc == 2 then About() elseif rc == 3 then if undo.GetCount() > 0 then undo.Undo() else dialog.MessageBox('No turn steps left to undo!',"Can't Undo") end else r = ParseRangeString(d.range.value) if r then for i = 1, d.repeating.value do band.DeleteAll() undo.Save() DoIt(r,d.rotation.value,d.twist.value,d.str.value,d.atom.value,d.skip.value) structure.WiggleAll(d.nwiggle.value) band.DeleteAll() end else dialog.MessageBox('Enter 1 or 2 numbers specifying the region to turn/twist','Range Error') end end end

Comments


brow42 Lv 1

This script will turn and/or twist a region of the protein. Unlike the tweak tool, it work on loops, not just sheets, and it can make a twist, not just straighten, and you can pick which end rotates, or both.

A good use is to continue the turn/twist around U-turns at the end of a sheet. Think of a rolled up towel, how if you rotate one end, it all wants to rotate.

The script has a built in undo function, so you can back up if you turn/twist too far, or in the wrong direction. There are 25 undo slots.

Rotation is defined by the "Right Hand Rule". If your right thumb points along the protein towards higher segment numbers, RIGHT rotation is the direction your fingers curl. Rotation rotates the entire region the same way; twist rotates the ends of the region in opposite directions. If you combine rotation and twist of the same strength, then you can make one end of the region be pinned.

A help panel explains all this. Or, you can just guess, and if it's wrong, hit the built-in undo button and reverse your settings.

It doesn't always work…maybe it's not strong enough, or maybe in a mostly folded protein, all the packed sidechains lock it in place…or maybe there are problems with the coordinate system. This recipe is experimental. I'm posting it so that you can try it out on Snow Flea Antifreeze protein, which has twisted sheets. I've added lots of knobs. Short regions seem best.

Version 0.1 beta will expire July 15 2012. At that time I'll add in any suggested improvements or bug fixes and release it as 1.0.

brow42 Lv 1

Removed beta status.

It seems the reason some times things won't twist is clashing by very large sidechains. They won't rotate through other sidechains/backbones.