Code
-- Copyright notice.
-- You may copy and paste at will. Plagiarize shamelessly!
-- End copyright notice
-- Mostly user-configurable globals
rebuild_length = 6 -- Length of sections to rebuild.
number_of_rebuilds = 12 -- It'll look for the best score from this number of rebuilds.
kMaxIterations = 10 -- Sanity check for the new wiggle loop
loops_only = true -- If true, will still allow a single non-loop residue in the rebuild segment
-- If false, non-loop residues will be temporarily converted to loops
exploration_puzzle = false
convert_to_loop = true
test_for_credit = false -- If true, test that all conditions are satisfied before registering an improvement
min_residue = 1
max_residue = 999
inner_sphere = {}
outer_sphere = {}
inner_sphere_radius = 12
outer_sphere_radius = 18
-- Use of quicksave slots
kOriginalStructureOrNewBest = 1
kBestPostRebuild_a = 2
kBestPostRebuild_b = 3
kBestPostRebuild_a_post_wiggle = 4
kTemp = 5
-- Globals
fixed_residues = {}
n_residues = 0
best_score = 0
-- Controls whether we should do a mini-fuze ( Shake at Low CI, Wiggle at CI of 1) after completion of the Rebuild sequence
-- A value of 0 means do it iff there's an overall improvement: a high negative value would mean do it always: a high positive
-- value would mean do it always.
post_rebuild_threshold = 0
-- For design
mutate_not_shake = false
-- Performance monitoring. Result intended for import into Excel as comma-delimited text
monit = false
monit_best_score = 0
monit_score_below_best = 0
monit_gain_from_shake = 0
monit_gain_from_nudge_wiggle = 0
monit_gain_from_fuse= 0
-- Begin
function r3 ( x )
-- Round to 3 decimal places
t = 10 ^ 3
return math.floor ( x*t + 0.5 ) / t
end
function GetScore ()
score = current.GetEnergyScore ()
if ( exploration_puzzle == true ) then
score = score * current.GetExplorationMultiplier ()
end
return score
end
function IsPuzzleMutable ()
for i = 1 , n_residues do
if ( structure.IsMutable ( i ) ) then
return true
end
end
return false
end
function Coprime ( n )
local primes = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101}
i = #primes
-- find the highest prime < 70% of the residue count and which is coprime with the number of residues
while ( i >= 1 ) do
if ( primes [ i ] < n*0.7 and n % primes [ i ] ~= 0 ) then
return primes [ i ]
end
i = i - 1
end
return 1
end
function IsSegmentALoop ( first , last )
-- Returns number of non-loop residues (helices or sheets)
n_non_loops = 0
for i = first , last do
if ( structure.GetSecondaryStructure ( i ) ~= "L" ) then
n_non_loops = n_non_loops + 1
end
end
return n_non_loops
end
function ConvertToLoop ( first , last )
if ( IsSegmentALoop ( first , last ) > 0 ) then
selection.DeselectAll ( )
selection.SelectRange ( first , last )
structure.SetSecondaryStructureSelected ( "L" )
end
end
function pseudorandom ( score )
-- Returns a pseudorandom number >= 0 and < 1.
-- Based on the fractional part of the score
if ( score >= 0 ) then
return score % 1
else
return (-score ) % 1
end
end
function GetListOfFixedResidues ()
for i = 1 , n_residues do
fixed_residues [ i ] = false
end
for i = 1 , n_residues do
seg_backbone_frozen, seg_sidechain_frozen = freeze.IsFrozen ( i )
if ( seg_backbone_frozen == true ) then
fixed_residues [ i ] = true
end
s = structure.IsLocked ( i )
if ( s == true ) then
fixed_residues [ i ] = true
end
end
end
function DoesSectionContainFixedResidues ( start_idx , end_idx )
for i = start_idx , end_idx do
if ( fixed_residues [ i ] == true ) then
return true
end
end
return false
end
function Wiggle ( step , threshold )
n_it = 0
new_score = GetScore ()
repeat
prev_score = new_score
structure.WiggleSelected ( step )
new_score = GetScore ()
n_it = n_it + 1
until ( ( math.abs ( new_score - prev_score ) < threshold ) or ( n_it > kMaxIterations ) )
end
function NudgeWiggle ()
recentbest.Save ()
behavior.SetClashImportance ( 0.07 )
structure.ShakeSidechainsSelected ( 1 )
behavior.SetClashImportance ( 1 )
Wiggle ( 4 , 0.1 )
score = GetScore()
recentbest.Restore ()
end
function SelectBestPostRebuild ()
save.Quickload ( kBestPostRebuild_a )
Wiggle ( 4 , 0.1 )
score_a = GetScore ()
save.Quicksave ( kBestPostRebuild_a_post_wiggle )
save.Quickload ( kBestPostRebuild_b )
Wiggle ( 4 , 0.1 )
score_b = GetScore ()
if ( score_a > score_b ) then
save.Quickload ( kBestPostRebuild_a_post_wiggle )
end
score_after_best_wiggle = GetScore ()
if ( mutate_not_shake == true ) then
structure.MutateSidechainsSelected ( 1 )
else
structure.ShakeSidechainsSelected ( 1 )
end
score_after_shake = GetScore ()
if ( score_after_shake > score_after_best_wiggle ) then
Wiggle ( 4 , 0.1 )
end
end
function Recovery ( start_x , end_x )
-- After rebuilding, if we're within striking distance of the best score ,
-- do a shake at Low CI/wiggle
init_score = GetScore ()
score_below_best = best_score - init_score
if ( monit ) then
monit_score_below_best = score_below_best
end
if ( score_below_best < post_rebuild_threshold ) then
NudgeWiggle ()
curr_score = GetScore ()
if ( monit == false ) then
print ( " " .. r3 ( score_below_best ) .. " " .. r3 ( curr_score - init_score ) )
end
if ( ( curr_score > best_score ) and
( test_for_credit == false or creditbest.AreConditionsMet () == true ) ) then
best_score = curr_score
save.LoadSecondaryStructure ()
save.Quicksave ( kOriginalStructureOrNewBest )
if ( monit == false ) then
print ( "Improvement to ".. r3 ( best_score ) )
end
end
elseif ( monit == false ) then
print ( " " .. r3 ( score_below_best ) )
end
end
function ConstructListOfResiduesWithinInnerSphere ( start_idx , end_idx )
for i = 1 , n_residues do
inner_sphere [ i ] = false
end
for i = 1 , n_residues do
for j = start_idx , end_idx do
if ( structure.GetDistance ( i , j ) < inner_sphere_radius ) then
inner_sphere [ i ] = true
end
end
end
end
function SelectInnerSphere ()
selection.DeselectAll ()
for i = 1 , n_residues do
if ( inner_sphere [ i ] == true ) then
selection.Select ( i )
end
end
end
function ConstructListOfResiduesWithinOuterSphere ( start_idx , end_idx )
for i = 1 , n_residues do
outer_sphere [ i ] = false
end
for i = 1 , n_residues do
for j = start_idx , end_idx do
if ( structure.GetDistance ( i , j ) < outer_sphere_radius ) then
outer_sphere [ i ] = true
end
end
end
end
function SelectOuterSphere ()
selection.DeselectAll ()
for i = 1 , n_residues do
if ( outer_sphere [ i ] == true ) then
selection.Select ( i )
end
end
end
function RebuildSeg ( start_idx , end_idx )
best_score_after_rebuild_and_shake_a = -99999
best_score_after_rebuild_and_shake_b = -99999
good_rebuild_found = false
ConstructListOfResiduesWithinInnerSphere ( start_idx , end_idx )
ConstructListOfResiduesWithinOuterSphere ( start_idx , end_idx )
for i = 1 , number_of_rebuilds do
save.Quickload ( kOriginalStructureOrNewBest )
if ( convert_to_loop == true ) then
ConvertToLoop ( start_idx , end_idx )
end
selection.DeselectAll ()
selection.SelectRange ( start_idx , end_idx )
structure.RebuildSelected ( 1 )
score_after_rebuild = GetScore ()
if ( math.abs ( score_after_rebuild - best_score ) >= 1e-5 ) then
good_rebuild_found = true
SelectInnerSphere ()
structure.ShakeSidechainsSelected ( 1 )
structure.WiggleSelected ( 2 )
score_after_shake_wiggle = GetScore ()
if ( score_after_shake_wiggle > math.min ( best_score_after_rebuild_and_shake_a , best_score_after_rebuild_and_shake_b ) ) then
if ( best_score_after_rebuild_and_shake_b < best_score_after_rebuild_and_shake_a ) then
best_score_after_rebuild_and_shake_b = score_after_shake_wiggle
save.Quicksave ( kBestPostRebuild_b )
else
best_score_after_rebuild_and_shake_a = score_after_shake_wiggle
save.Quicksave ( kBestPostRebuild_a )
end
end
end
end -- for i
if ( good_rebuild_found == true ) then
SelectOuterSphere ()
SelectBestPostRebuild ()
return 1
else
return 0
end
end
function RebuildAllAtSpecifiedLength ( rebuild_length )
local inc
max_possible_residue = max_residue - rebuild_length + 1
n_possible_segs = max_possible_residue - min_residue + 1
r = pseudorandom ( best_score )
start_idx = min_residue + n_possible_segs * r
start_idx = start_idx - start_idx % 1
inc = Coprime ( n_possible_segs )
-- The point of this Coprime, start_idx business is so we go through the protein in a
-- nonuniform way. Rather than rebuilding 1-4, 2-5 , 3-6 for example, we might do 21-24, 53-57, 3-6
-- or something like that
candidate_section_found = false
for i = 1 , n_possible_segs do
end_idx = start_idx + rebuild_length - 1
assert ( start_idx >= min_residue and end_idx <= max_residue , "Range error" )
save.LoadSecondaryStructure ()
if ( ( DoesSectionContainFixedResidues ( start_idx , end_idx ) == false ) and
( loops_only == false or
( loops_only == true and IsSegmentALoop ( start_idx , end_idx ) < 2 ) ) ) then
if ( monit ) then
monit_best_score = best_score
monit_score_below_best = 0
monit_gain_from_shake = 0
monit_gain_from_nudge_wiggle = 0
monit_gain_from_fuse = 0
end
candidate_section_found = true
rb = rb + 1
if ( monit == false ) then
print ( "rb ".. rb .. " " .. start_idx .."-" .. end_idx .. " (" ..i .. "/" .. n_possible_segs .. ")" )
end
if ( RebuildSeg ( start_idx , end_idx ) == 1 ) then
Recovery ( start_idx , end_idx )
if ( monit ) then
print ( r3 ( monit_best_score ) .. " , " ..
start_idx .. " , " ..
end_idx .. " , " ..
r3 ( monit_score_below_best ) .. " , " ..
r3 ( monit_gain_from_shake ) .. " , " ..
r3 ( monit_gain_from_nudge_wiggle ) .. " , " ..
r3 ( monit_gain_from_fuse ) )
end
end
end
start_idx = start_idx + inc
if ( start_idx > max_possible_residue ) then
start_idx = start_idx - n_possible_segs
end
end -- for i
if ( candidate_section_found == false ) then
print ( "No rebuildable sections found" )
exit (0)
end
end
function GetParameters ()
local dlog = dialog.CreateDialog ( "Loop rebuild 5.0 : New Chapters" )
dlog.rb_length = dialog.AddSlider ( "Rebuild length" , rebuild_length , 3 , 10 , 0 )
dlog.min_residue = dialog.AddSlider ( "Min residue" , 1 , 1 , n_residues , 0 )
dlog.max_residue = dialog.AddSlider ( "Max residue" , n_residues , 1 , n_residues , 0 )
dlog.loops = dialog.AddCheckbox ( "Loops only" , loops_only )
dlog.cnvt_loops = dialog.AddCheckbox ( "Convert to loops" , convert_to_loop )
dlog.n_rebuilds = dialog.AddSlider ( "N rebuilds" , number_of_rebuilds , 2 , 50 , 0 )
dlog.div_1 = dialog.AddLabel ( "__________________________________________" )
dlog.inner_radius = dialog.AddSlider ( "Inner sphere" , inner_sphere_radius , 1 , 30 , 1 )
dlog.outer_radius = dialog.AddSlider ( "Outer sphere" , outer_sphere_radius , 1 , 40 , 1 )
design_puzzle = IsPuzzleMutable ()
dlog.div_2 = dialog.AddLabel ( "__________________________________________" )
if ( design_puzzle == true ) then
dlog.mutate= dialog.AddCheckbox ( "Mutate" , true )
end
if ( exploration_puzzle == true ) then
dlog.exploration = dialog.AddCheckbox ( "Exploration score" , true )
end
dlog.credit_check = dialog.AddCheckbox ( "Check conditions met " , test_for_credit )
dlog.ok = dialog.AddButton ( "OK" , 1 )
dlog.cancel = dialog.AddButton ( "Cancel" , 0 )
if ( dialog.Show ( dlog ) > 0 ) then
rebuild_length = dlog.rb_length.value
min_residue = dlog.min_residue.value
max_residue = dlog.max_residue.value
loops_only = dlog.loops.value
convert_to_loop = dlog.cnvt_loops.value
number_of_rebuilds = dlog.n_rebuilds.value
inner_sphere_radius = dlog.inner_radius.value
outer_sphere_radius = dlog.outer_radius.value
if ( design_puzzle == true ) then
mutate_not_shake = dlog.mutate.value
end
if ( exploration_puzzle == true ) then
exploration_puzzle = dlog.exploration
end
test_for_credit = dlog.credit_check.value
return true
else
return false
end
end
function main()
band.DisableAll ()
n_residues = structure.GetCount ()
save.SaveSecondaryStructure ()
rb = 0
save.Quicksave ( kOriginalStructureOrNewBest )
behavior.SetClashImportance ( 1 )
if ( current.GetExplorationMultiplier () > 0 ) then
exploration_puzzle = true
end
if ( GetParameters () == false ) then
return -- graceful exit
end
best_score = GetScore ()
print ( "Start score : " .. r3 ( best_score ) )
print ( "Rebuild length : " .. rebuild_length )
if ( loops_only == true ) then
print ( "Loops only" )
else
print ( "Loops, sheets, and helices" )
if ( convert_to_loop == true ) then
print ( "Converting to loops" )
end
end
max_residue = math.min ( n_residues , max_residue )
min_residue = math.max ( 1 , min_residue )
if ( max_residue < min_residue + rebuild_length - 1 ) then
print ( "Rebuild range error." )
print ( "Max residue (" .. max_residue .. ") must be greater than or equal to Min residue (" .. min_residue .. ")" )
print ( "plus Rebuild Length (" .. rebuild_length .. ")" )
return
end
print ( "Rebuild range " .. min_residue .. " to " .. max_residue )
GetListOfFixedResidues ()
if ( monit ) then
print ( "Start score" .. " , " ..
"Start idx" .. " , " ..
"End idx" .. " , " ..
"Score below best" .. " , " ..
"Gain from shake" .. " , " ..
"Gain from nudge wiggle" .. " , " ..
"Gain from fuse" )
end
while ( true ) do
RebuildAllAtSpecifiedLength ( rebuild_length )
end
save.Quickload ( kOriginalStructureOrNewBest )
band.EnableAll ()
end
function cleanup ()
print ( "Cleaning up" )
behavior.SetClashImportance ( 1.0 )
save.Quickload ( kOriginalStructureOrNewBest )
save.LoadSecondaryStructure ()
band.EnableAll ()
end
--main ()
xpcall ( main , cleanup )