Code
--iwdn worm
--version 1.1 28.04.2021
--Script to perform local wiggles/mutates/shakes along the protein.
--What it does:
--Performs local wiggle/mutate/shake along a protein.
--If the user has selected residues before this recipe is run, then the worm will only run along these segments. Otherwise all non-locked segments will be treated.
--The advantage of this worm-implementation is that it will not only act on the sidechains on the protein but also on adjacent sidechains for example on a target-binder. Set this via the "Radius" slider.
--Also, point- and objective-loss is monitored and it is reverted to a previous state so that no point- and especially objective-loss is possible.
--This recipe can sometimes gain many points in short times while keeping the structure intact.
--Just play around with it and see what it can do for you.
--Happy folding to all!
--version history
--1.0:
--Initial version. Only for internal use. Imlementation of basic functionality.
--1.1:
--Brushed up for release. Changed a few settings.
--28.04.2012 Bugfix: Removed unused code around the error-source "toWorkON".
--Variables and Constants
version = "1.1"
dia = {} --Global GUI
--************* Change if desired *******************
qs_idx = 33 --Index to start for quicksave slots
--*********** End: Change if desired ****************
function wait(seconds)
local start = os.time()
repeat until os.time() > start + seconds
end
function round(inNum)
return inNum-inNum%0.001
end
--Determine which sidechains shall be processed. The user needs to select them before running this recipe!
toWorkOn = {}
toWorkOnIdx = 1
function findToWorkOn()
residues = structure.GetCount()
for m=1,residues do
if (selection.IsSelected(m) == true) then
toWorkOn[toWorkOnIdx] = m
toWorkOnIdx = toWorkOnIdx+1
end
end
--If user has not selected anything beforehand then choose all non-locked residues.
if (toWorkOnIdx == 1) then
for m=1,residues do
if (structure.IsLocked(m) == false) then
toWorkOn[toWorkOnIdx] = m
toWorkOnIdx = toWorkOnIdx+1
end
end
end
--If still toWorkOn is empty then this is an error.
if (toWorkOnIdx == 1) then
print("Error. No residues to work on could be found!")
return
end
end
function getScore()
if (metrics_enable == 1) then
tmpVal = metric.GetBonusTotal()+current.GetScore()
return tmpVal
else
return current.GetScore()
end
end
function mysplit(inputstr, sep)
if sep == nil then
sep = "%s"
end
local t={}
for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
table.insert(t, str)
end
return t
end
function checkFilters()
--Check the objectives and store for later reference.
local currFilters = {}
local filterNames = filter.GetNames()
local filterBonus_tmp = nil
if (filterNames[1] ~= nil) then
for m=1,#filterNames do
local filterName = filterNames[m]
if (filter.HasBonus(filterName)) then
--Store here filters that may not degrade in score. These will be protected with the save/restore-scheme.
if (string.find(string.lower(filterName), "core") ~= nil and string.find(string.lower(filterName), "existence") ~= nil) then
filterBonus_tmp = filter.GetBonus(filterName)
currFilters[#currFilters+1] = {filterBonus_tmp, filterName}
--print(round(currFilters[#currFilters][1]) .. " Pts: " .. currFilters[#currFilters][2])
elseif (string.find(string.lower(filterName), "ideal") ~= nil and string.find(string.lower(filterName), "loop") ~= nil) then
filterBonus_tmp = filter.GetBonus(filterName)
currFilters[#currFilters+1] = {filterBonus_tmp, filterName}
--print(round(currFilters[#currFilters][1]) .. " Pts: " .. currFilters[#currFilters][2])
elseif (string.find(string.lower(filterName), "hydrogen") ~= nil and string.find(string.lower(filterName), "network") ~= nil) then
filterBonus_tmp = filter.GetBonus(filterName)
currFilters[#currFilters+1] = {filterBonus_tmp, filterName}
--print(round(currFilters[#currFilters][1]) .. " Pts: " .. currFilters[#currFilters][2])
elseif (string.find(string.lower(filterName), "disulfide") ~= nil and string.find(string.lower(filterName), "count") ~= nil) then
filterBonus_tmp = filter.GetBonus(filterName)
currFilters[#currFilters+1] = {filterBonus_tmp, filterName}
--print(round(currFilters[#currFilters][1]) .. " Pts: " .. currFilters[#currFilters][2])
elseif (string.find(string.lower(filterName), "buried") ~= nil and string.find(string.lower(filterName), "unsats") ~= nil) then
if (dia.cbx04.value == true) then
filterBonus_tmp = filter.GetBonus(filterName)
currFilters[#currFilters+1] = {filterBonus_tmp, filterName}
--print(round(currFilters[#currFilters][1]) .. " Pts: " .. currFilters[#currFilters][2])
end
end
end
end
--print(round(filter.GetBonusTotal()) .. " Pts: Total Filter Bonus")
end
return currFilters
end
function worm(w_toWorkOn, w_modus, w_startIdx, w_step, w_radius, w_iters, w_prot)
--Instead of wiggling globally, this function wiggles locally multiple times at different positions.
--Objectives are monitored so that none degrades. Especially core and loops. Uses qs33.
--Changed this so that this function always only does 1 turn. If you want to run multiple turns then just call this function again.
--w_prot=0: unprotected. 1: Objectives only are monitored. 2: Score is monitored. 3: Objectives and score are monitored.
local w_startFilters = checkFilters()
local w_currScore = getScore()
local w_residues = structure.GetCount()
--Store solution for later restore
save.Quicksave(qs_idx)
--Start the worm-loop
--Go through the residues to process and wiggle in the vicinity.
local w_currCenter = nil
local w_currVici = {}
for n=w_startIdx,#w_toWorkOn,w_step do
w_currCenter = w_toWorkOn[n]
w_currVici = {}
--Determine which segments are in the vicinity of the center
w_currVici[#w_currVici+1] = w_currCenter
for o=1,w_residues do
if (o ~= w_currCenter) then
w_currDist = structure.GetDistance(w_currCenter, o)
if (w_currDist < w_radius) then
w_currVici[#w_currVici+1] = o
end
end
end --End: Determine vicinity
--Now apply the desired operation onto all segments in the vicinity.
selection.DeselectAll()
for o=1,#w_currVici do
selection.Select(w_currVici[o]) --select residues in the vicinity
end
if (w_modus == 1) then --wiggle
structure.LocalWiggleSelected(w_iters, true, true) --backbone, sidechains
elseif (w_modus == 2) then --mutate
structure.MutateSidechainsSelected(w_iters)
else --shake
structure.ShakeSidechainsSelected(w_iters)
end
selection.DeselectAll()
--Restore previous solution if loops were damaged or core-bonus lost.
local w_currFilters = checkFilters()
local w_doRestore = 0
for o=1,#w_currFilters do
if (w_currFilters[o][1] < w_startFilters[o][1]) then
w_doRestore = 1
break
elseif (w_currFilters[o][1] > w_startFilters[o][1]) then
--Update the risen objective so that it will not be lost again in later turns.
--startFilters[o][1] = currFilters[o][1] --This may lead to problems?!
end
--print(round(currFilters[o][1]) .. " Pts: " .. currFilters[o][2])
end
if (w_prot == 0) then --unprotected. May decrease in score.
save.Quicksave(qs_idx)
w_currScore = getScore()
elseif (w_prot == 1) then --Protected objectives. May decrease in score.
if (w_doRestore == 1) then
save.Quickload(qs_idx)
else
save.Quicksave(qs_idx)
w_currScore = getScore()
end
elseif (w_prot == 2) then --Protected score
if (getScore() <= w_currScore) then
save.Quickload(qs_idx)
else
save.Quicksave(qs_idx)
w_currScore = getScore()
end
else --Protected objectives AND score
if (w_doRestore == 1) then
save.Quickload(qs_idx) --Reload previous quicksave since we lost some bonus.
else
if (getScore() <= w_currScore) then
save.Quickload(qs_idx) --If we did not increase in score then fall-back to previous solution.
else
save.Quicksave(qs_idx) --Overwrite previous highscore-solution with this one since we achieved an improvement.
w_currScore = getScore()
end
end
end
end --End: Main worm-loop
end --End: worm
function main()
print("Running iwdn worm version " .. version .. "...")
findToWorkOn() --Is required in the GUI
--Show GUI
dia = dialog.CreateDialog("Iwdn worm " .. version)
--dia.txb01 = dialog.AddTextbox("ToWorkOn", "0.4 0.3 0.2 0.15 0.1 0.09 0.08 0.07 0.06 0.05 0.04 0.03")
dia.lbl01 = dialog.AddLabel("Settings for worm operations (just choose one of the next 3):")
dia.cbx01 = dialog.AddCheckbox("Do Wiggle", true)
dia.cbx02 = dialog.AddCheckbox("Do Mutate", false)
dia.cbx03 = dialog.AddCheckbox("Do Shake", false)
dia.sli01 = dialog.AddSlider("Iters", 6, 1, 100, 0)
dia.sli02 = dialog.AddSlider("Radius", 8, 1, 20, 0)
dia.sli05 = dialog.AddSlider("Step", 3, 1, 20, 0)
dia.sli03 = dialog.AddSlider("Total turns", 1, 1, 30, 0)
dia.cbx04 = dialog.AddCheckbox("Avoid BUNs", false)
dia.but01 = dialog.AddButton("OK", 1)
dia.but02 = dialog.AddButton("Cancel", 0)
tmpBack = dialog.Show(dia)
if (tmpBack ~= 0) then
else
print("Iwdn worm " .. version .. " has finished.")
return
end
--Run the worm
local w_stIdx = 1
for m=1,dia.sli03.value do --Total turns loop
if (dia.cbx01.value == true) then --Wiggle
print("Wiggle worm protected (" .. dia.sli01.value .. ") turn " .. m .. "/" .. dia.sli03.value .. "...")
worm(toWorkOn, 1, w_stIdx, dia.sli05.value, dia.sli02.value, dia.sli01.value, 3) --Protect score and objectives.
elseif (dia.cbx02.value == true) then --Mutate
print("Mutate worm protected (" .. dia.sli01.value .. ") turn " .. m .. "/" .. dia.sli03.value .. "...")
worm(toWorkOn, 2, w_stIdx, dia.sli05.value, dia.sli02.value, dia.sli01.value, 3) --Protect score and objectives.
elseif (dia.cbx03.value == true) then --Shake
print("Shake worm protected (" .. dia.sli01.value .. ") turn " .. m .. "/" .. dia.sli03.value .. "...")
worm(toWorkOn, 3, w_stIdx, dia.sli05.value, dia.sli02.value, dia.sli01.value, 3) --Protect score and objectives.
end
w_stIdx = w_stIdx+1 --Wrap the start-index
if (w_stIdx >= dia.sli05.value) then
w_stIdx = 1
end
end
print("Iwdn worm " .. version .. " has finished.")
end --main
--xpcall(main, cleanup)
main()