Code
--[[ Void Crusher Lipid
Voids Killer by rav3n_pl
script is searching for possible banding across voids.
Because we not have any voids detection in Lua, I do some math to find them
Not always perfect, but mostly works :)
Tvdl: 09-01-2012
Added extra option to pull all the bands in one go,
pulls harder, if wanted, on hydro's
Works also as a stabilizer (like Hydrophobic script)
Compacts the protein
Warning: when used all at once will accept a loss
If so the previous score is in slot 3
Tvdl: 12-07-2012
- Made totally V2
MDC: 2-19-2014
Added Wiggle Factor
BK: 2-22-*-2014
restore recursive wiggle
BK: 3.03 infinite run
BK: 3.04 change options on each loop
BK: 3.05 added set notes
BK: 3.1.0 atoms on IsHydrophilic pull & more hydrophobics
BK: 3.1.1 fixed main loop
BK: 3.1.2 fixed delete bands
BK: 4.0.0 added bands to existing bands (for symmetric): if the user previously add bands to symmetrics,
the recipe will be able to add bands to symmetrics and detect voids between the 2 monomers
BK: 4.1.0 optional band to existing bands (TO DO: recognizes sym puzzles)
WARNING: end point is only in one direction. If you want the 2 end points, you have to add a reverse band
(this is only possible for bands to main monomer)
BK: 4.1.1 added a log to recall scores on each steps (jeff101's display)
BK: 4.1.2 SemiRandomStr added (slightly randomizes band strength on pull all)
BK: 4.1.2 Lipid: replace phobic by lipid (will put hydrophillic inside, IsHydrophilic outside)
BK: 4.1.3 added CI function for debugging, sorry
]]--
Version="4.1.3"
recipename="Void Crusher Lipid "..Version
-- Handy shorts module
normal= (current.GetExplorationMultiplier() == 0)
--CI=behavior.SetClashImportance
segCnt=structure.GetCount()
segCnt2=segCnt
while structure.GetSecondaryStructure(segCnt2)=="M" do segCnt2=segCnt2-1 end
DIST2USERBANDS= false
ExistingBands=band.GetCount()
if ExistingBands >0 then DIST2USERBANDS = true end
print("Starting "..recipename.. " on\n puzzle "..(puzzle.GetName()))
print(' with puzzle ID '..(puzzle.GetPuzzleID())..' and '..ExistingBands..' user-supplied bands.\n ')
CIfactor=1
function CI(CInr)
behavior.SetClashImportance(CInr*CIfactor)
end
-- Score functions
function Score()
if normal==nil or normal==true then
-- FIX for big negatives
local total= current.GetEnergyScore()
if total < -999999 and total > -1000001 then total=SegScore() end
return total
else
return current.GetScore()
end
end
function SegScore()
local total=8000
for i=1,segCnt2 do
total=total+current.GetSegmentEnergyScore(i)
end
return total
end
function RBScore()
if normal then
return recentbest.GetEnergyScore()
else
return recentbest.GetScore()
end
end
function round3(x)--cut all afer 3-rd place
return x-x%0.001
end
--START SET NOTES BY PD
--[[ Set note with author, recipe and big steps -- By Pauldunn
module to paste it in existing recipe, by BK
]]--
--HOW TO include in a recipe?
--1a) COPY from here ================
function InitNotes(recipename)
local recipename=recipename or ""
note_number=structure.GetCount()
for seg=structure.GetCount(),1,-1 do
if structure.GetNote(seg)~="" then break end
note_number=seg
end
print(string.format("Recording "..recipename.." results in Note for segment %i",note_number))
starting_score=current.GetScore()
--structure.SetNote(note_number,string.format("(%s) %.3f + %s(%i) %.3f",user.GetPlayerName(),starting_score,recipename,loop_count,current.GetScore()))
end
function SetNote(note_number, starting_score, recipename, loop_count)
local recipename=recipename or ""
local starting_score=starting_score or 0
local loop_count=loop_count or 1
--print(string.format("Recording "..recipename.." results in Note for segment %i",note_number))
structure.SetNote(note_number,string.format("(%s) %.3f + %s(%i) %.3f",user.GetPlayerName(),starting_score,recipename,loop_count,current.GetScore()))
end
InitNotes(recipename) -- WARNING: and mach "recipename" with the recipename of the recipe
--1b) COPY to here. ================
--2) PASTE somewhere to the beginning of your recipe.
--3a) COPY from here ---------------
--SetNote(note_number, starting_score, recipename, loop_count) -- WARNING: and mach "recipename" and "loop_count" with the names of the recipe
--3b) COPY to here --------------
--4) PASTE at the end of the main loop function of your recipe, at the end of the cleanup function, at the end of the recipe
--better loop_count a global variable
--END SET NOTES BY PD
bestScore=Score()
function SaveBest()
local g=Score()-bestScore
if g>0 then
if g>0.01 then print("Gained another "..round3(g).." pts.") end
bestScore=Score()
SetNote(note_number, starting_score, recipename, loop_count)
save.Quicksave(3)
end
end
-- New WiggleFactor
WF=1
-- Wiggle function
-- Optimized due to Susumes ideas
-- Note the extra parameter to be used if only selected parts must be done
function Wiggle(how, iters, minppi,onlyselected) -- 22/02/2014 reset recursive wiggle
--score conditioned recursive wiggle/shake
--fixed a bug, absolute difference is the threshold now
if how==nil then how="wa" end
if iters==nil then iters=3 end
if minppi==nil then minppi=0.1 end
if onlyselected==nil then onlyselected=false end
local wf=1
if maxCI then wf=WF end
--print("Wiggle FactorA= ",WF)
if iters>0 then
--iters=iters-1
local sp=Score()
if onlyselected then
if how == "s" then
-- Shake is not considered to do much in second or more rounds
structure.ShakeSidechainsSelected(1)
return
elseif how == "wb" then structure.WiggleSelected(2*wf*iters,true,false)
elseif how == "ws" then structure.WiggleSelected(2*wf*iters,false,true)
elseif how == "wa" then structure.WiggleSelected(2*wf*iters,true,true)
end
else
if how == "s" then
-- Shake is not considered to do much in second or more rounds
structure.ShakeSidechainsAll(1)
return
elseif how == "wb" then structure.WiggleAll(2*wf*iters,true,false)
elseif how == "ws" then structure.WiggleAll(2*wf*iters,false,true)
elseif how == "wa" then structure.WiggleAll(2*wf*iters,true,true)
end
end
if Score()-sp > minppi then return Wiggle(how, iters, minppi,onlyselected) end
iters=iters-1 -- 22/02/2014
end
end
-- end of handy shorts module
-- Standard Fuze module
-- Picks up all gains by using recentbest
function FuzeEnd()
CI(1)
Wiggle("wa",1)
Wiggle("s",1)
Wiggle()
if RBScore()> Score() then recentbest.Restore() end
SaveBest()
end
function Fuze1(ci1,ci2)
CI(ci1)
Wiggle("s",1)
CI(ci2)
Wiggle("wa",1)
end
function Fuze2(ci1,ci2)
CI(ci1)
Wiggle("wa",1)
CI(1)
Wiggle("wa",1)
CI(ci2)
Wiggle("wa",1)
end
function reFuze(scr,slot)
local s=Score()
if s<scr then
save.Quickload(slot)
else
scr=s
save.Quicksave(slot)
end
return scr
end
function Fuze(slot)
local scr=Score()
recentbest.Save()
Fuze1(0.3,0.6) FuzeEnd()
scr=reFuze(scr,slot)
Fuze2(0.3,1)
if RBScore()>Score() then recentbest.Restore() end
SaveBest()
scr=reFuze(scr,slot)
Fuze1(0.05,1)
if RBScore()>Score() then recentbest.Restore() end
SaveBest()
scr=reFuze(scr,slot)
Fuze2(0.7,0.5) FuzeEnd()
scr=reFuze(scr,slot)
Fuze1(0.07,1)
if RBScore()>Score() then recentbest.Restore() end
SaveBest()
reFuze(scr,slot)
if RBScore()>Score() then recentbest.Restore() end
SaveBest()
end
-- end standard Fuze module
-- Distance lib
--
distances={} -- a list of distances between segments only
distancesb={} -- a list of distances between segments and end bands
distScore=Score()
function getDist() -- 1 dim for speed
if #distances<1 or distScore ~= Score() then
distScore=Score()
distances[1]=0
print("Calculating distances...")
for i=1,segCnt do --filling table
for j=i+1,segCnt do --not counting from beginning - no need :)
distances[i*segCnt+j]=structure.GetDistance(i,j)
end
end
print("Done")
end
end
function dist(a,b)
if a==b then return 0 end
if a>b then a,b=b,a end
return distances[a*segCnt+b]
end
function getDist2Band() -- 1 dim for speed
if #distancesb<1 or distScore ~= Score() then
distScore=Score()
distancesb[1]=0
print("Calculating distances to end bands...")
for i=1,segCnt do --filling table
if DIST2USERBANDS then -- New 15/12/2015
for j=1,ExistingBands do
distancesb[i*segCnt+j]=dist2band(i,j)
end
end
end
print("Done")
end
end
function distSeg2band(a,b)
if b==0 then return 0 end
return distancesb[a*segCnt+b]
end
function dist2band(s,b) -- distance between a segment and a band end point VERY SLOW !!
local iBand= 0
iBand = band.AddToBandEndpoint(s, b)
local distance=band.GetLength(iBand)
band.Delete(iBand)
return distance
end
-- Safe band module
--ExistingBands=band.GetCount()
--if ExistingBands >0 then DIST2USERBANDS = true end
function disableExistingBands()
for i=1,ExistingBands do band.Disable(i) end
end
function enableExistingBands()
for i=1,ExistingBands do band.Enable(i) end
end
function bandDisableAll()
for i=ExistingBands+1,band.GetCount() do band.Disable(i) end
end
function bandEnableAll()
for i=ExistingBands+1,band.GetCount() do band.Enable(i) end
end
function bandDeleteAll()
for i=ExistingBands+1,band.GetCount() do band.Delete(ExistingBands+1) end
end
function bandSetStrengthAll(str) -- randomized
if SemiRandomStr then
local minBS2, maxBS2=minBS, maxBS
if str-minBS > maxBS-str then minBS2= 2*str - maxBS else maxBS2= 2* str - minBS end
local strbase=str
for i=ExistingBands+1,band.GetCount() do
strbase= random2numbers(minBS2,maxBS2)
band.SetStrength(i,strbase)
end
else
for i=ExistingBands+1,band.GetCount() do band.SetStrength(i,str) end
end
end
function bandGetCount()
return band.GetCount()-ExistingBands
end
-- end safe band module
function down(x)
return x-x%1
end
function round(x)--cut all afer 3-rd place
return x-x%0.001
end
function qStab()
CI(0.1)
Wiggle("s",1)
if fastQstab==false then
CI(0.4)
Wiggle("wa",1)
CI(1)
Wiggle("s",1)
end
CI(1)
Wiggle()
end
math.randomseed(Score())
math.random(100) -- Because first random is not random
function random2numbers(n1,n2) --random function returns int or float depends on input vars
if n2==nil and n1==nil then
return math.random() --float 0-1
else
if n2==nil then
if n1%1==0 then
return math.random(n1) --integer 1-n1
else
return math.random()*n1 --float 0-n1
end
else
if n1%1==0 and n2%1==0 then
return math.random(n1,n2) --integer between
else
return math.random()*(n2-n1)+n1 --float between, including 0
--return math.random(n1,n2) --float between BK 17/02/2015, this is also correct
end
end
end
end
function Sort(tab,items)
for x=1,items do
for y=x+1,#tab do
if tab[x][2]>tab[y][2] then
tab[x],tab[y]=tab[y],tab[x]
end
end
end
return tab
end
function BuildTargetList(first) -- to segments or end points of user bands
targetList={} -- reset list of segments and endpoints
for first = 1,segCnt do
targetList[#targetList + 1] = {"s",i}
end
if DIST2USERBANDS then -- New 15/12/2015
for i = 1,ExistingBands do
targetList[#targetList + 1] = {"b",i}
end
end
end
function mkBand(a) --make band if found void in area of that segment
print("Banding segment "..a)
getDist() -- distances between all segments
getDist2Band() -- distances between all end band and all segs
local t={}--there we store possible segments
local ts={}--there we store possible voids between symmetrics
local first=1
if allatonce then first=a+2 end
if first > segCnt then return false end
--BuildTargetList(first)-- to segments or end points of user bands
for b=first,segCnt do --test all segments
if useRegionBool[a] or useRegionBool[b] then -- case of segments to segments
local ab=dist(a,b) --distance between segments
voids=false -- voids between segments
if ab>minLength and ab < maxLength and math.abs(a-b) >= minDist then --no void if less
--print(a," ",b," ",ab)
local void=true
for c=1,segCnt do --searching that is any segment between them
local ac=dist(a,c)
local bc=dist(b,c)
if ac~=0 and bc~=0 and ac<ab and bc<ab and ac>4 and bc>4 then
if ac+bc<ab+1.5
then void=false break --no void there for sure
end
end
end
if void==true and (not allatonce or a<b) then
t[#t+1]={a,b}
voids=true
end
end
end
end
if DIST2USERBANDS then -- New 15/12/2015
for b= 1, ExistingBands do
if useRegionBool[a] and b>0 then -- case of symmetric, bands to end user bands
local ab=distSeg2band(a,b)
voidss=false -- voids between segs and bands (monomers in symmetric)
if ab>minLength and ab < maxLength then
local voidb=true
for c=1,segCnt do --searching that is any segment between them
local ac=dist(a,c)
local bc=distSeg2band(c,b)
if ac~=0 and bc~=0 and ac<ab and bc<ab and ac>4 and bc>4 then
if ac+bc<ab+1.5
then voidb=false break --no void there for sure
end
end
end
if voidb then
ts[#ts+1]={a,b}
voidss=true
end
end
end
end
end
if voids or voidss then
local tt= #t + #ts
print("Found "..tt.." possible bands across voids")
else
print("No voids found")
end
if voids then
--print("Found "..#t.." possible bands across voids (seg to seg)")
for i=1,#t do
local s=t[i][1]
local e=t[i][2]
local atoms=0
local atome=0
if BlueInside or BlueSidechain then
if not structure.IsHydrophobic(s) and structure.GetAtomCount(s)>0 then
atoms=1
if BlueSidechain then atoms=structure.GetAtomCount(s) end
end
if not structure.IsHydrophobic(e) and structure.GetAtomCount(e)>0 then
atome=1
if BlueSidechain then atome=structure.GetAtomCount(e) end
end
end
band.AddBetweenSegments(s,e,atoms,atome)
local d=dist(s,e)
d=d-compFrac
if d<3 then d=3 end
if d>20 then d=20 end
local bnr=band.GetCount()
band.SetGoalLength(bnr,d)
if allatonce then
if not structure.IsHydrophobic(s) or not structure.IsHydrophobic(e) then band.SetStrength(bnr,pullextrahydro*allBS)
else band.SetStrength(bnr,allBS) end
end
end
end
if voidss then -- voids between segs and bands (monomers in symmetric)
--print("Found "..#ts.." possible bands across voids (seg to end band)")
for i=1,#ts do
local s=ts[i][1]
local b=ts[i][2]
local atoms=0
if BlueInside or BlueSidechain then -- WARNING: here I favour hydrophobic to end points
-- because end points (on symmetric) are supposed to be outside of the protein !!! Good for H-Bonds
if structure.IsHydrophobic(s) and structure.GetAtomCount(s)>0 then --
atoms=1
if BlueSidechain then atoms=structure.GetAtomCount(s) end
end
end
band.AddToBandEndpoint(s, b, atoms)
local d=distSeg2band(s,b)
d=d-compFrac
if d<3 then d=3 end
if d>20 then d=20 end
local bnr=band.GetCount()
band.SetGoalLength(bnr,d)
if allatonce then
if not structure.IsHydrophobic(s) then band.SetStrength(bnr,pullextrahydro*allBS)
else band.SetStrength(bnr,allBS) end
end
end
end
end
function SaveRB()
if RBScore() > Score() then
save.Quicksave(9)
recentbest.Restore()
SaveBest()
save.Quickload(9)
end
end
function Pull(List) -- List is a list of segments
disableExistingBands()
if List==nil then for i=1,segCnt do mkBand(i) end
else for i=1,#List do mkBand(List[i]) end
end
if bandGetCount() >0 then -- it counts new bands only
CI(pullingCI)
-- Make an estimation of the required strength
if lastAllBS > 0 then lastBS=lastAllBS/bandGetCount() end
if lastBS < minBS then lastBS=minBS end
if lastBS > maxBS then lastBS=maxBS end
recentbest.Save()
local loss=math.abs(down(Score()*maxLoss/100))
for str=lastBS,maxBS,0.11 do --search enough band strenght to move
recentbest.Restore()
ss=Score()
if not allatonce then bandSetStrengthAll(str) end
Wiggle("wb",1)
if ss-Score()>loss then
lastAllBS=(str-0.1)*bandGetCount()
break
end
end
bandDeleteAll()
SaveRB() --because sometimes it missing fractions
print("Stabilizing...")
CI(1)
recentbest.Save() --after pulling
qStab()
if bestScore-Score()<doFuze or allatonce then
SaveBest()
print("Fuzing....")
Fuze(4)
SaveBest()
end
if not allatonce then save.Quickload(3) --load best state
end
print("Current score: "..round3(Score()).." VC gain: "..round3(Score()-StartScore))
end
end
loop_count=0
function KillVoids() -- main loops are here
loop_count=loop_count+1 -- for setnotes
if allatonce then lastBS=allBS minBS=allBS maxBS=allBS end
lastBS=minBS
local s={}
getDist() --calculate distances now
getDist2Band() -- calculate distances of all segs with ends of all existing bands
if #Speclist > 0 then
for i=1,#Speclist do s[#s+1]={Speclist[i], current.GetSegmentEnergyScore(Speclist[i])} end
else
for i=1,segCnt do
s[#s+1]={i, current.GetSegmentEnergyScore(i)}
end
end
if Vworst==true then
Sort(s,#s)
end
if Vrandom==true then -- not really random, it's always the same !!
for i=1,#s do
local r=math.random(#s)
s[i],s[r]=s[r],s[i]
end
end
if allatonce then Pull()
else
local Speclist2={} --Clear list
for i=1,#s/Combinum do
print("Loop "..loop..". Kill "..i.." of "..(#s-#s%Combinum)/Combinum.." started.")
for j=1,Combinum do Speclist2[j]=s[Combinum*i-Combinum+j][1] end
Pull(Speclist2)
end
end
end
-- Segment set and list module
-- Notice that most functions assume that the sets are well formed
-- (=ordered and no overlaps)
-- 02-05-2012 TvdL Free to use for non commercial purposes
function SegmentListToSet(list)
local result={}
local f=0
local l=-1
table.sort(list)
for i=1,#list do
if list[i] ~= l+1 and list[i] ~= l then
-- note: duplicates are removed
if l>0 then result[#result+1]={f,l} end
f=list[i]
end
l=list[i]
end
if l>0 then result[#result+1]={f,l} end
--print("list to set")
--SegmentPrintSet(result)
return result
end
function SegmentSetToList(set)
local result={}
for i=1,#set do
--print(set[i][1],set[i][2])
for k=set[i][1],set[i][2] do
result[#result+1]=k
end
end
return result
end
function SegmentCleanSet(set)
-- Makes it well formed
return SegmentListToSet(SegmentSetToList(set))
end
function SegmentInvertSet(set,maxseg)
-- Gives back all segments not in the set
-- maxseg is added for ligand
local result={}
if maxseg==nil then maxseg=structure.GetCount() end
if #set==0 then return {{1,maxseg}} end
if set[1][1] ~= 1 then result[1]={1,set[1][1]-1} end
for i=2,#set do
result[#result+1]={set[i-1][2]+1,set[i][1]-1}
end
if set[#set][2] ~= maxseg then result[#result+1]={set[#set][2]+1,maxseg} end
return result
end
function SegmentInList(s,list)
table.sort(list)
for i=1,#list do
if list[i]==s then return true
elseif list[i]>s then return false
end
end
return false
end
function SegmentInSet(set,s)
for i=1,#set do
if s>=set[i][1] and s<=set[i][2] then return true
elseif s<set[i][1] then return false
end
end
return false
end
function SegmentJoinList(list1,list2)
local result=list1
if result == nil then return list2 end
for i=1,#list2 do result[#result+1]=list2[i] end
table.sort(result)
return result
end
function SegmentJoinSet(set1,set2)
return SegmentListToSet(SegmentJoinList(SegmentSetToList(set1),SegmentSetToList(set2)))
end
function SegmentCommList(list1,list2)
local result={}
table.sort(list1)
table.sort(list2)
if #list2==0 then return result end
local j=1
for i=1,#list1 do
while list2[j]<list1[i] do
j=j+1
if j>#list2 then return result end
end
if list1[i]==list2[j] then result[#result+1]=list1[i] end
end
return result
end
function SegmentCommSet(set1,set2)
return SegmentListToSet(SegmentCommList(SegmentSetToList(set1),SegmentSetToList(set2)))
end
function SegmentSetMinus(set1,set2)
return SegmentCommSet(set1,SegmentInvertSet(set2))
end
function SegmentPrintSet(set)
print(SegmentSetToString(set))
end
function SegmentSetToString(set)
local line = ""
for i=1,#set do
if i~=1 then line=line..", " end
line=line..set[i][1].."-"..set[i][2]
end
return line
end
function SegmentSetInSet(set,sub)
if sub==nil then return true end
-- Checks if sub is a proper subset of set
for i=1,#sub do
if not SegmentRangeInSet(set,sub[i]) then return false end
end
return true
end
function SegmentRangeInSet(set,range)
if range==nil or #range==0 then return true end
local b=range[1]
local e=range[2]
for i=1,#set do
if b>=set[i][1] and b<=set[i][2] then
return (e<=set[i][2])
elseif e<=set[i][1] then return false end
end
return false
end
function SegmentSetToBool(set)
local result={}
for i=1,structure.GetCount() do
result[i]=SegmentInSet(set,i)
end
return result
end
--- End of Segment Set module
-- Module Find Segment Types
function FindMutables()
local result={}
for i=1,structure.GetCount() do if structure.IsMutable(i) then result[#result+1]=i end end
return SegmentListToSet(result)
end
function FindFrozen()
local result={}
for i=1,structure.GetCount() do if freeze.IsFrozen(i) then result[#result+1]=i end end
return SegmentListToSet(result)
end
function FindLocked()
local result={}
for i=1,structure.GetCount() do if structure.IsLocked(i) then result[#result+1]=i end end
return SegmentListToSet(result)
end
function FindSelected()
local result={}
for i=1,structure.GetCount() do if selection.IsSelected(i) then result[#result+1]=i end end
return SegmentListToSet(result)
end
function FindAAtype(aa)
local result={}
for i=1,structure.GetCount() do
if structure.GetSecondaryStructure(i)== aa then result[#result+1]=i end
end
return SegmentListToSet(result)
end
function FindAminotype(at)
-- This one returns a list not a set
local result={}
for i=1,structure.GetCount() do
if structure.GetAminoAcid(i) == at then result[#result+1]=i end
end
return result
end
-- end Module Find Segment Types
-- Module AskSelections
-- 02-05-2012 Timo van der Laan, Free to use for non commercial purposes
function AskForSelections(title,mode)
local result={{1,structure.GetCount()}} -- All segments
if mode == nil then mode={} end
if mode.askloops==nil then mode.askloops=true end
if mode.asksheets==nil then mode.asksheets=true end
if mode.askhelixes==nil then mode.askhelixes=true end
if mode.askligands==nil then mode.askligands=false end
if mode.askselected==nil then mode.askselected=true end
if mode.asknonselected==nil then mode.asknonselected=true end
if mode.askmutateonly==nil then mode.askmutateonly=true end
if mode.askignorelocks==nil then mode.askignorelocks=true end
if mode.askignorefrozen==nil then mode.askignorefrozen=true end
if mode.askranges==nil then mode.askranges=true end
if mode.defloops==nil then mode.defloops=true end
if mode.defsheets==nil then mode.defsheets=true end
if mode.defhelixes==nil then mode.defhelixes=true end
if mode.defligands==nil then mode.defligands=false end
if mode.defselected==nil then mode.defselected=false end
if mode.defnonselected==nil then mode.defnonselected=false end
if mode.defmutateonly==nil then mode.defmutateonly=false end
if mode.defignorelocks==nil then mode.defignorelocks=false end
if mode.defignorefrozen==nil then mode.defignorefrozen=false end
local Errfound=false
repeat
local ask = dialog.CreateDialog(title)
if Errfound then
ask.E1=dialog.AddLabel("Try again, ERRORS found, check output box")
result={{1,structure.GetCount()}} --reset start
Errfound=false
end
if mode.askloops then
ask.loops = dialog.AddCheckbox("Work on loops",mode.defloops)
elseif not mode.defloops then
ask.noloops= dialog.AddLabel("Loops will be auto excluded")
end
if mode.askhelixes then
ask.helixes = dialog.AddCheckbox("Work on helixes",mode.defhelixes)
elseif not mode.defhelixes then
ask.nohelixes= dialog.AddLabel("Helixes will be auto excluded")
end
if mode.asksheets then
ask.sheets = dialog.AddCheckbox("Work on sheets",mode.defsheets)
elseif not mode.defsheets then
ask.nosheets= dialog.AddLabel("Sheets will be auto excluded")
end
if mode.askligands then
ask.ligands = dialog.AddCheckbox("Work on ligands",mode.defligands)
elseif not mode.defligands then
ask.noligands= dialog.AddLabel("Ligands will be auto excluded")
end
if mode.askselected then ask.selected = dialog.AddCheckbox("Work only on selected",mode.defselected) end
if mode.asknonselected then ask.nonselected = dialog.AddCheckbox("Work only on nonselected",mode.defnonselected) end
if mode.askmutateonly then ask.mutateonly = dialog.AddCheckbox("Work only on mutateonly",mode.defmutateonly) end
if mode.askignorelocks then
ask.ignorelocks =dialog.AddCheckbox("Dont work on locked ones",true)
elseif mode.defignorelocks then
ask.nolocks=dialog.AddLabel("Locked ones will be auto excluded")
end
if mode.askignorefrozen then
ask.ignorefrozen = dialog.AddCheckbox("Dont work on frozen",true)
elseif mode.defignorefrozen then
ask.nofrozen=dialog.AddLabel("Frozen ones will be auto excluded")
end
if mode.askranges then
ask.R1=dialog.AddLabel("Or put in segmentranges. Above selections also count")
ask.ranges=dialog.AddTextbox("Ranges","")
end
ask.OK = dialog.AddButton("OK",1) ask.Cancel = dialog.AddButton("Cancel",0)
if dialog.Show(ask) > 0 then
-- We start with all the segments including ligands
if mode.askloops then mode.defloops=ask.loops.value end
if not mode.defloops then
result=SegmentSetMinus(result,FindAAtype("L"))
end
if mode.asksheets then mode.defsheets=ask.sheets.value end
if not mode.defsheets then
result=SegmentSetMinus(result,FindAAtype("E"))
end
if mode.askhelixes then mode.defhelixes=ask.helixes.value end
if not mode.defhelixes then
result=SegmentSetMinus(result,FindAAtype("H"))
end
if mode.askligands then mode.defligands=ask.ligands.value end
if not mode.defligands then
result=SegmentSetMinus(result,FindAAtype("M"))
end
if mode.askignorelocks then mode.defignorelocks=ask.ignorelocks.value end
if mode.defignorelocks then
result=SegmentSetMinus(result,FindLocked())
end
if mode.askignorefrozen then mode.defignorefrozen=ask.ignorefrozen.value end
if mode.defignorefrozen then
result=SegmentSetMinus(result,FindFrozen())
end
if mode.askselected then mode.defselected=ask.selected.value end
if mode.defselected then
result=SegmentCommSet(result,FindSelected())
end
if mode.asknonselected then mode.defnonselected=ask.nonselected.value end
if mode.defnonselected then
result=SegmentCommSet(result,SegmentInvertSet(FindSelected()))
end
if mode.askranges and ask.ranges.value ~= "" then
local rangetext=ask.ranges.value
local function Checknums(nums)
-- Now checking
if #nums%2 ~= 0 then
print("Not an even number of segments found")
return false
end
for i=1,#nums do
if nums[i]==0 or nums[i]>structure.GetCount() then
print("Number "..nums[i].." is not a segment")
return false
end
end
return true
end
local function ReadSegmentSet(data)
local nums = {}
local NoNegatives='%d+' -- - is not part of a number
local result={}
for v in string.gfind(data,NoNegatives) do
table.insert(nums, tonumber(v))
end
if Checknums(nums) then
for i=1,#nums/2 do
result[i]={nums[2*i-1],nums[2*i]}
end
result=SegmentCleanSet(result)
else Errfound=true result={} end
return result
end
local rangelist=ReadSegmentSet(rangetext)
if not Errfound then
result=SegmentCommSet(result,rangelist)
end
end
end
until not Errfound
return result
end
-- end of module AskSelections
--MAIN is in askMode here
function askMode()
local ask = dialog.CreateDialog("Voidcrusher "..Version.." Runmode")
ask.l1=dialog.AddLabel("Run specified number of kills at a time")
ask.Combi = dialog.AddSlider("Nr of segments: ",Combinum,1,10,0)
ask.allatonce=dialog.AddCheckbox("Or pull all in one go",allatonce)
ask.l3=dialog.AddLabel("Or do multiple runs on 1 to 6 segments")
ask.multi=dialog.AddSlider("Repeat multi",multi,0,20,0)
ask.l2 = dialog.AddLabel("The choices above also apply if selections are made")
ask.selected=dialog.AddCheckbox("Set selection where to pull from",false)
ask.selection=dialog.AddCheckbox("Select segments where 1 bandend must be",false)
ask.BlueInside=dialog.AddCheckbox("Hide Hydrophilic chains",BlueInside)
ask.BlueSidechain=dialog.AddCheckbox("Band end of sidechains",BlueSidechain)
if DIST2USERBANDS then
ask.DIST2USERBANDS=dialog.AddCheckbox("Band to end of user bands",DIST2USERBANDS)
end
ask.l4 = dialog.AddLabel("Modify fine tuning options, depended on mode")
ask.WF = dialog.AddSlider("WiggleFactor:",WF,1,5,0)
--print("Wiggle FactorB= ",ask.WF.value)
ask.modOptions=dialog.AddCheckbox("Modify options",false)
ask.OK = dialog.AddButton("OK",1) ask.Cancel = dialog.AddButton("Cancel",0)
if dialog.Show(ask) > 0 then
Combinum=ask.Combi.value
allatonce=ask.allatonce.value
multi=ask.multi.value
BlueInside=ask.BlueInside.value
BlueSidechain=ask.BlueSidechain.value
if DIST2USERBANDS then -- possibility to disable in case of non symmetric but wanted keeping bands
DIST2USERBANDS=ask.DIST2USERBANDS.value
end
WF=ask.WF.value
-- print("Wiggle FactorC= ",ask.WF.value)
if ask.selected.value then
local SelMode={}
SelMode.askligands=true --override the defaults
SelMode.defligands=true
SelMode.defignorelocks=false
SelMode.defignorefrozen=false
local PullFrom=AskForSelections("Set where to pull from",SelMode)
for i=1,segCnt do
if SegmentInSet(PullFrom,i) then Speclist[#Speclist+1]=i end
end
end
if ask.selection.value then
local SelMode={}
SelMode.askligands=true --override the defaults
SelMode.defligands=true
SelMode.askignorelocks=false
SelMode.defignorelocks=true
SelMode.defignorefrozen=false
useRegion=AskForSelections("At least one bandend must be",SelMode)
else
useRegion={{1,segCnt}}
useRegion=SegmentSetMinus(useRegion,FindLocked())
end
useRegionBool=SegmentSetToBool(useRegion)
if ask.modOptions.value then
AskOptions()
end
MAIN()
end
end
function ChangeOptions()
print("Changing all options:")
if minDist==1 then minDist=15 else minDist= minDist-1 end--minimum segment distance
if minLength==2 then minLength= 10 else minLength=minLength-1 end --minimum spatial distance
maxLength=50 --maximum spatial distance
fastQstab = not fastQstab --1s1w then true, double if false
if compFrac==1 then compFrac= 3 else compFrac=compFrac-1 end --how much shorter band should be
-- Defaults here VVV
Vworst=not Vworst --start form worst scoring one
Vrandom=not Vrandom --true --go it in random order
-- if both are false then it will band form 1st to last
if multi==0 then multi=1 else multi=0 end-- Multirun overrides all other options
if Combinum==10 then Combinum=1 else Combinum=1+1 end-- Nr of segments to be treated in 1 go
if doFuze==-5 then doFuze=5 else doFuze= doFuze-1 end --run fuzes when close to saved best (negative - run if gain after qstab)
if pullingCI<=0.1 then pullingCI=0.90 else pullingCI=pullingCI-0.1 end--clash importance during pull
Speclist={}
minBS=0.12 --absolute minimum band strength
if maxBS==5 then maxBS=1 else maxBS=maxBS+1 end--absolute maximum band strength
if maxLoss==5 then maxLoss=1 else maxLoss=maxLoss+1 end --pull till perc loss (ie 1 on 10`000 ptsy = pull till 100 pt loss after pull)
-- New options
allatonce=not allatonce --false -- set to true if all at once
pullextrahydro=1.1 --multiplier for extra pull on hydro segments
allBS=0.12 -- strength if all
lastAllBS=0
lastBS=minBS
BlueInside= not BlueInside
BlueSidechain= not BlueSidechain
SemiRandomStr = not SemiRandomStr
PrintOptions()
end
function AskOptions() -- fine tuning
local ask = dialog.CreateDialog("Finetune options Voidcrusher "..Version)
if not allatonce or #Speclist > 0 then
ask.l1=dialog.AddLabel("Band strength during pull")
ask.BandsAbsMin=dialog.AddSlider("Minimum",minBS,0.1,1,2)
ask.BandsAbsMax=dialog.AddSlider("Maximum",maxBS,0.1,2,2)
ask.SemiRandomStr=dialog.AddCheckbox("and semi-random",SemiRandomStr)
end
if not allatonce then
ask.l2=dialog.AddLabel("Order of treatement")
ask.random=dialog.AddCheckbox("Random",Vrandom)
ask.worst=dialog.AddCheckbox("Worst first",Vworst)
ask.l3=dialog.AddLabel("Pull harder if loss is less")
ask.maxLoss=dialog.AddSlider("Percentage",maxLoss,0,2,1)
ask.l4 = dialog.AddLabel("Run fuze if qstab is close to recent best")
ask.doFuze = dialog.AddSlider("Neg, only after gain",doFuze,-10,20,1)
else
ask.l11=dialog.AddLabel("Band strength to pull with")
ask.allBS = dialog.AddSlider("Band strength",allBS,0.1,1,2)
ask.l21 = dialog.AddLabel("Multiplier to pull hydrophobics more")
ask.hydro = dialog.AddSlider("Phobic factor: ",pullextrahydro,0.5,3,1)
end
ask.lx1= dialog.AddLabel("Maximum band length")
ask.maxLength=dialog.AddSlider("maxLength",maxLength,15,100,1)
ask.l5 = dialog.AddLabel("Clash importance while pulling")
ask.CI = dialog.AddSlider("Clash importance",pullingCI,0.3,1,2)
ask.OK = dialog.AddButton("OK",1) ask.Cancel = dialog.AddButton("Cancel",0)
if dialog.Show(ask) > 0 then
if not allatonce or #Speclist > 0 then
minBS=ask.BandsAbsMin.value
maxBS=ask.BandsAbsMax.value
SemiRandomStr=ask.SemiRandomStr.value
end
if not allatonce then
maxLoss=ask.maxLoss.value
Vrandom=ask.random.value
Vworst=ask.worst.value
doFuze=ask.doFuze.value
else
allBS=ask.allBS.value
pullextrahydro=ask.hydro.value
end
maxLength=ask.maxLength.value
pullingCI=ask.CI.value
end
end
function PrintOptions()
print("Options: ")
print("minimum segment distance: "..minDist) --minimum segment distance
print("minimum spatial distance: "..minLength) --minimum spatial distance
print("maximum spatial distance: "..maxLength) --maximum spatial distance
if fastQstab then print("fastQstab") end --1s1w then true, double if false
print("Band should be "..compFrac.." Amstr. shorter") --how much shorter band should be
-- Defaults here VVV
if Vworst then print("start from worst scoring one") end
if Vrandom then print("go it in random order") end
-- if both are false then it will band form 1st to last
if not Vworst and not Vrandom then print("band form 1st to last") end
if multi==0 then print("Multirun (overrides all other options)") end
print("Nr of segments to be treated in 1 go: "..Combinum)-- Nr of segments to be treated in 1 go
print("Fuze when distance to Best < "..doFuze) -- (negative - run if gain after qstab)
print("Pulling CI= "..pullingCI) --clash importance during pull
print("Min band strength= "..minBS) --absolute minimum band strength
print("Maximum band strength ="..maxBS) --absolute maximum band strength
if SemiRandomStr then print ("Semi-random strength") end
print("pull till loss < max "..maxLoss.." %") --pull till perc loss (ie 1 on 10`000 ptsy = pull till 100 pt loss after pull)
-- New options
if allatonce then print("all at once") end--false -- set to true if all at once
print("multiplier for extra pull on hydro segments: "..pullextrahydro)
if BlueInside then print ("Hide Hydrophilic chains") end
if BlueSidechain then print ("Band end of sidechains") end
end
loop=0
function MAIN() -- called by askMode() just above
--thus dialog with user is already done just before
StartScore=Score()
save.Quicksave(3)
print("Starting Void Crusher "..Version.." by BK, Tvdl and rav3n_pl")
print("Start score: "..round3(StartScore))
PrintOptions()
ssstr=(round(Score()))
for step=1, 10000 do
loop= loop+1
local sls= Score()
local les=sls
print("##########################")
print("MAIN LOOP "..loop.."/10000")
genScore=les
gen= step
print("")
print("Generation: "..gen..", score: "..round(Score())..", gain: "..round(Score()-StartScore).." ("..(os.date())..")")
if multi > 0 then
allatonce=false
for i=1,multi do
for j=1,6 do
Combinum=j
KillVoids()
end
end
else KillVoids()
end
les=Score()
print("Loop "..loop.." gained "..round3(les-sls))
genEndScore=Score()
genGain=genEndScore-genScore
if gen>1 and (gen-1)==5*down((gen-1)/5) then -- New 18/1/2016 jeff101 log display
ssstr=(ssstr..'\n ') -- start new line every 5 generations
end
if genGain>=0 then
ssstr=(ssstr..' + '..round(genGain))
else
ssstr=(ssstr..' - '..(-round(genGain)))
end
print(ssstr..' = '..round(genEndScore))
print("Total VC gain= "..round3(les-StartScore).." from "..round3(StartScore).." to "..round3(Score()))
ChangeOptions()
end
end
--- OPTIONS THERE! vvv
useRegion={}
useRegionBool={}
minDist=15 --minimum segment distance
minLength=10 --minimum spatial distance
maxLength=50 --maximum spatial distance
fastQstab = true --1s1w then true, double if false
compFrac=3 --how much shorter band should be (in Amstroms)
-- Defaults here VVV
Vworst=false --start form worst scoring one
Vrandom=true --true --go it in random order
-- if both are false then it will band form 1st to last
multi=0 -- Multirun overrides all other options
Combinum=1 -- Nr of segments to be treated in 1 go
doFuze=5 --run fuzes when close to saved best (negative - run if gain after qstab)
pullingCI=0.90 --clash importance during pull
Speclist={}
minBS=0.12 --absolute minimum band strength
maxBS=1 --absolute maximum band strength
maxLoss=1 --pull till perc loss (ie 1 on 10`000 ptsy = pull till 100 pt loss after pull)
-- New options
allatonce=false --false -- set to true if all at once
pullextrahydro=1.3 --multiplier strength extra pull on IsHydrophilic segments
allBS=0.12 -- strength if all
lastAllBS=0
lastBS=minBS
SemiRandomStr= false
BlueInside= true -- band to IsHydrophilic sidechains to pull (could help to turn)
BlueSidechain=false
targetList={} -- list of segments and endpoints, to be built later
--END OF OPTIONS ^^^
function Cleanup(err)
print("Resetting CI and best score, removing extra bands")
save.Quickload(3)
CI(1)
if bandGetCount() >0 then
bandDeleteAll()
end
SetNote(note_number, starting_score, recipename, loop_count)
print(err)
end
xpcall(askMode,Cleanup)