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 = 8 -- It'll look for the best score from this number of rebuilds.
ss_criterion = 2 -- Controls whether to rebuild a section based on secondary structure
convert_to_loop = false -- If true, any non-loop residues will be temporarily converted to loops
test_for_credit = false -- If true, test that all conditions are satisfied before registering an improvement
keep_bands = true
min_residue = 1
max_residue = 999
kInvalidScore = -99999
use_remix = true
inner_sphere = {}
outer_sphere = {}
kInnerSphereRadius = 10
kOuterSphereRadius = 18
kDefaultWiggleDuration = 12
kLowCiWiggle = 0.2
pw_threshold_value = 30
score_type = 1
-- Use of quicksave slots
kOriginalStructureOrNewBest = 1
kBestPostRebuild_a = 2
kBestPostRebuild_b = 3
kBestPostRebuild_a_post_wiggle = 4
kTemp = 5
kRemixQuicksaveStart = 20
-- Globals
original_secondary_structure = {}
fixed_residues = {}
original_slow_filters_setting = 0
n_residues = 0
best_score = 0
score_after_bc_wiggle = 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 = 2
-- For design
mutate_not_shake = false
-- For monitoring
loss_from_low_ci_wiggle = {}
original_residues = {}
new_residues = {}
start_time = 0
-- Amino acids. Hydrophobics first.
single_letter_codes = { "g","a","v","l","i","m","f","w","p","s","t","c","y","n","q","d","e","k","r","h"}
three_letter_codes = { "Gly","Ala","Val","Leu","Ile","Met","Phe","Trp","Pro","Ser","Thr","Cys","Tyr","Asn","Gln","Asp","Glu","Lys","Arg","His"}
-- Begin
function r3 ( x )
-- Round to 3 decimal places
t = 10 ^ 3
return math.floor ( x*t + 0.5 ) / t
end
function GetScore ()
if ( score_type == 1 ) then
score = current.GetScore ()
elseif ( score_type == 2 ) then
score = current.GetEnergyScore ()
elseif ( score_type == 3 ) then
score = current.GetScore ()
score = score * current.GetExplorationMultiplier ()
elseif ( score_type == 4 ) then
score = 0
for i = 1 , n_residues do
score = score + current.GetSegmentEnergySubscore ( i , "hiding" )
end
elseif ( score_type == 5 ) then
score = 0
for i = 1 , n_residues do
score = score + current.GetSegmentEnergySubscore ( i , "bonding" )
end
elseif ( score_type == 6 ) then
behavior.SetSlowFiltersDisabled ( false )
score_with_filters = current.GetScore ()
behavior.SetSlowFiltersDisabled ( true )
score_without_filters = current.GetScore ()
score = score_with_filters - score_without_filters
elseif ( score_type == 7 ) then
behavior.SetSlowFiltersDisabled ( false )
score = current.GetScore ()
behavior.SetSlowFiltersDisabled ( true )
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 aa1_to_aa3 ( k )
for j = 1, 20 do
if ( k == single_letter_codes [ j ] ) then
return three_letter_codes [ j ]
end
end
return "Unk"
end
function DoesPuzzleHaveSlowFilters ()
init_setting = behavior.GetSlowFiltersDisabled ()
if ( init_setting == false ) then
score_without_sf = current.GetScore ()
behavior.SetSlowFiltersDisabled ( true )
score_with_sf = current.GetScore ()
else
score_with_sf = current.GetScore ()
behavior.SetSlowFiltersDisabled ( false )
score_without_sf = current.GetScore ()
end
behavior.SetSlowFiltersDisabled ( init_setting )
if ( math.abs ( score_without_sf - score_with_sf ) >1e-3 ) then
return true
else
return false
end
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 SegmentComposition ( first , last )
-- Returns number of residues of each secondary structure type
n_loop_residues = 0
n_helix_residues = 0
n_sheet_residues = 0
for i = first , last do
ss = structure.GetSecondaryStructure ( i )
if ( ss == "L" ) then
n_loop_residues = n_loop_residues + 1
elseif ( ss == "H" ) then
n_helix_residues = n_helix_residues + 1
elseif ( ss == "E" ) then
n_sheet_residues = n_sheet_residues + 1
end
end
return n_loop_residues , n_helix_residues , n_sheet_residues
end
function IsSegmentRebuildable ( first , last )
-- Rebuildable in the sense that the secondary structure satisfies the specified criteria
n_loop_residues , n_helix_residues , n_sheet_residues = SegmentComposition ( first , last )
if ( ss_criterion == 1 ) then
-- Loops only
if ( n_helix_residues > 0 or n_sheet_residues > 0 ) then
return false
else
return true
end
elseif ( ss_criterion == 2 ) then
-- Loops with one non-loop residue
if ( n_helix_residues + n_sheet_residues > 1 ) then
return false
else
return true
end
elseif ( ss_criterion == 3 ) then
-- Loops or sheets
if ( n_helix_residues > 0 ) then
return false
else
return true
end
elseif ( ss_criterion == 4 ) then
return true
end
end
function ConvertToLoop ( first , last )
-- Slightly inefficient to call SegmentComposition twice
n_loop_residues , n_helix_residues , n_sheet_residues = SegmentComposition ( first , last )
if ( n_helix_residues + n_sheet_residues > 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 ShakeLowCIWiggle ( c_score )
save.Quicksave ( kTemp )
behavior.SetClashImportance ( 0.10 )
structure.ShakeSidechainsSelected ( 1 )
behavior.SetClashImportance ( 1 )
structure.WiggleSelected ( kDefaultWiggleDuration )
score = GetScore ()
if ( score < c_score ) then
save.Quickload ( kTemp )
score = c_score
end
end
function FinalIdealize ( c_score , start_idx , end_idx )
kFallApartThreshold = 1000
save.Quicksave ( kTemp )
selection.DeselectAll ()
selection.SelectRange ( start_idx , end_idx )
structure.IdealizeSelected ()
score_after_idealize = GetScore ()
selection.SelectAll ()
if ( ( c_score - score_after_idealize ) > kFallApartThreshold ) then
structure.WiggleAll ( 1, false , true ) -- wiggle sidechains
end
if ( math.abs ( score - c_score ) > 1e-3 ) then
structure.WiggleSelected ( 12 )
score = GetScore ()
if ( score < c_score ) then
save.Quickload ( kTemp )
score = c_score
end
end
end
function WiggleNudge ( c_score )
save.Quicksave ( kTemp )
structure.WiggleSelected ( kDefaultWiggleDuration )
aa_score = GetScore ()
if ( aa_score < c_score ) then
save.Quickload ( kTemp )
aa_score = c_score -- Cater to filter-induced score decrease
end
save.Quicksave ( kTemp )
behavior.SetClashImportance ( kLowCiWiggle )
structure.WiggleSelected ( 1 )
table.insert ( loss_from_low_ci_wiggle , aa_score - GetScore () )
behavior.SetClashImportance ( 1 )
structure.WiggleSelected ( kDefaultWiggleDuration )
score = GetScore ()
if ( score < aa_score ) then
save.Quickload ( kTemp )
end
end
function WiggleTwoBestCandidatesAndSelectBest ()
save.Quickload ( kBestPostRebuild_a )
structure.WiggleSelected ( kDefaultWiggleDuration )
score_a = GetScore ()
save.Quicksave ( kBestPostRebuild_a_post_wiggle )
if ( best_score_after_rebuild_and_shake_b > kInvalidScore ) then -- To cater for single rebuild
save.Quickload ( kBestPostRebuild_b )
structure.WiggleSelected ( kDefaultWiggleDuration )
score_b = GetScore ()
if ( score_a > score_b ) then
save.Quickload ( kBestPostRebuild_a_post_wiggle )
end
end
end
function PostWiggle ()
init_score = GetScore ()
save.Quicksave ( kTemp )
if ( score_type == 4 or score_type == 5 or score_type == 6 ) then
return 1 -- Hiding or bonding
elseif ( best_score - init_score < pw_threshold_value ) then
if ( mutate_not_shake == true ) then
structure.MutateSidechainsSelected ( 1 )
else
structure.ShakeSidechainsSelected ( 1 )
end
score = GetScore ()
if ( score < init_score ) then
save.Quickload ( kTemp ) -- Cater for filters causing a decrease
score = init_score
end
WiggleNudge ( score )
return 1
else
return 0
end
end
function FinalFuse ( start_x , end_x )
-- After rebuilding, if we've got a new best score (tweakable by adjusting post_rebuild_threshold ) ,
-- do a shake at low CI followed by a wiggle
init_score = GetScore ()
score_below_best = best_score - init_score
if ( score_type == 4 or score_type == 5 or score_type == 6 ) then
return -- Hiding or bonding
elseif ( score_below_best < post_rebuild_threshold ) then
-- ShakeLowCIWiggle ( init_score )
FinalIdealize ( init_score , start_x , end_x )
return
else
return
end
end
function RecordImprovement ()
curr_score = GetScore ()
if ( ( test_for_credit == false ) or ( creditbest.AreConditionsMet () == true ) ) then
best_score = curr_score
save.LoadSecondaryStructure ()
save.Quicksave ( kOriginalStructureOrNewBest )
print ( "Improvement to ".. r3 ( best_score ) )
return 1
else
return 0
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 ) < kInnerSphereRadius ) 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 ) < kOuterSphereRadius ) 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 RebuildPreamble ( start_idx , end_idx )
save.Quickload ( kOriginalStructureOrNewBest )
if ( convert_to_loop == true ) then
ConvertToLoop ( start_idx , end_idx )
end
selection.DeselectAll ()
selection.SelectRange ( start_idx , end_idx )
end
function RebuildSeg ( start_idx , end_idx )
local i
local n_rebuilds
local n_good_rebuilds = 0
best_score_after_rebuild_and_shake_a = kInvalidScore
best_score_after_rebuild_and_shake_b = kInvalidScore
ConstructListOfResiduesWithinInnerSphere ( start_idx , end_idx )
ConstructListOfResiduesWithinOuterSphere ( start_idx , end_idx )
if ( use_remix == true ) then
RebuildPreamble ( start_idx , end_idx )
n_rebuilds = structure. RemixSelected ( kRemixQuicksaveStart , number_of_rebuilds )
else
n_rebuilds = number_of_rebuilds
end
for i = 1 , n_rebuilds do
if ( use_remix == true ) then
save.Quickload ( kRemixQuicksaveStart -1 + i )
else
RebuildPreamble ( start_idx , end_idx )
structure.RebuildSelected ( 1 )
end
score_after_rebuild = GetScore ()
if ( math.abs ( score_after_rebuild - best_score ) >= 1e-5 ) then
n_good_rebuilds = n_good_rebuilds + 1
SelectInnerSphere ()
structure.ShakeSidechainsSelected ( 1 )
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
return n_good_rebuilds
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
( IsSegmentRebuildable ( start_idx , end_idx ) == true ) ) then
candidate_section_found = true
rb = rb + 1
print ( "rb ".. rb .. " " .. start_idx .."-" .. end_idx .. " (" ..i .. "/" .. n_possible_segs .. ")" )
if ( RebuildSeg ( start_idx , end_idx ) > 0 ) then
SelectOuterSphere ()
WiggleTwoBestCandidatesAndSelectBest ()
score_after_bc_wiggle = GetScore ()
if ( PostWiggle () == 1 ) then
score_after_post_wiggle = GetScore ()
FinalFuse ( start_idx , end_idx )
score_after_final_fuse = GetScore ()
if ( score_after_final_fuse > best_score ) then
print ( " " .. r3 ( score_after_bc_wiggle - best_score ) ..
" " .. r3 ( score_after_post_wiggle - score_after_bc_wiggle ) ..
" " .. r3 ( score_after_final_fuse - score_after_post_wiggle ) )
RecordImprovement ()
else
print ( " " .. r3 ( score_after_bc_wiggle - best_score ) ..
" " .. r3 ( score_after_post_wiggle - score_after_bc_wiggle ) )
end
else
print ( " " .. r3 ( score_after_bc_wiggle - best_score ) )
end
else
print ( "Skipped" )
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 PrintParameters ()
if ( score_type == 1 ) then
print ( "Score type : Normal" )
elseif ( score_type == 2 ) then
print ( "Score type : Energy" )
elseif ( score_type == 3 ) then
print ( "Score type : Exploration" )
elseif ( score_type == 4 ) then
print ( "Score type : Hiding" )
elseif ( score_type == 5 ) then
print ( "Score type : Bonding" )
elseif ( score_type == 6 ) then
print ( "Score type : Filters" )
elseif ( score_type == 7 ) then
print ( "Score type : Normal/Slow Filters" )
end
print ( "Start score : " .. r3 ( best_score ) )
print ( "Rebuild length : " .. rebuild_length )
if ( ss_criterion == 1 ) then
print ( "Loops only" )
elseif ( ss_criterion == 2 ) then
print ( "Loops + 1" )
elseif ( ss_criterion == 3 ) then
print ( "Loops + sheets" )
elseif ( ss_criterion == 4 ) then
print ( "Any" )
end
if ( convert_to_loop == true ) then
print ( "Converting to loops" )
end
if ( use_remix == true ) then
print ( "Using remix" )
end
print ( "Rebuild range " .. min_residue .. " to " .. max_residue )
print ( "N rebuilds " .. number_of_rebuilds )
end
function GetOptionalParameters ()
local dlog = dialog.CreateDialog ( "Options" )
dlog.pw_threshold = dialog.AddSlider ( "Post sw threshold" , pw_threshold_value , 0 , 200 , 0 )
dlog.cnvt_loops = dialog.AddCheckbox ( "Convert to loops" , convert_to_loop )
dlog.keep_bands = dialog.AddCheckbox ( "Keep bands" , keep_bands )
dlog.ok = dialog.AddButton ( "OK" , 1 )
dlog.cancel = dialog.AddButton ( "Cancel" , 0 )
if ( dialog.Show ( dlog ) > 0 ) then
pw_threshold_value = dlog.pw_threshold.value
convert_to_loop = dlog.cnvt_loops.value
keep_bands = dlog.keep_bands.value
return true
else
return false
end
end
function GetParameters ()
local dlog = dialog.CreateDialog ( "Loop rebuild 8.0" )
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.rebuild_criterion = dialog.AddSlider ( "Rebuild criterion" , ss_criterion , 1 , 4 , 0 )
dlog.rc = dialog.AddLabel ( "1 = L only : 2 = L only + 1 : 3 = L + E : 4 = Any" )
dlog.n_rebuilds = dialog.AddSlider ( "N rebuilds" , number_of_rebuilds , 1 , 40 , 0 )
dlog.use_remix = dialog.AddCheckbox ( "Use remix" , use_remix )
dlog.div_1 = dialog.AddLabel ( "__________________________________________" )
design_puzzle = IsPuzzleMutable ()
if ( design_puzzle == true ) then
dlog.mutate= dialog.AddCheckbox ( "Mutate" , true )
end
if ( DoesPuzzleHaveSlowFilters () == true ) then
score_type = 7
end
dlog.score_type = dialog.AddSlider ( "Score type" , score_type , 1 , 7 , 0 )
dlog.tp = dialog.AddLabel ( "1 = Normal : 2 = Energy : 3 = Explore : 4 = Hiding" )
dlog.tp_2 = dialog.AddLabel ( "5 = Bonding : 6 = Filters : 7 = Normal for Slow Filters" )
dlog.credit_check = dialog.AddCheckbox ( "Check conditions met " , test_for_credit )
dlog.ok = dialog.AddButton ( "OK" , 1 )
dlog.cancel = dialog.AddButton ( "Cancel" , 0 )
dlog.other_options = dialog.AddButton ( "Other options" , 2 )
return_code = dialog.Show ( dlog )
if ( return_code > 0 ) then
rebuild_length = dlog.rb_length.value
min_residue = dlog.min_residue.value
max_residue = dlog.max_residue.value
ss_criterion = dlog.rebuild_criterion.value
number_of_rebuilds = dlog.n_rebuilds.value
use_remix = dlog.use_remix.value
if ( design_puzzle == true ) then
mutate_not_shake = dlog.mutate.value
end
score_type = dlog.score_type.value
test_for_credit = dlog.credit_check.value
end
return return_code
end
function main()
n_residues = structure.GetCount ()
for i = 1, n_residues do
original_secondary_structure [ i ] = structure.GetSecondaryStructure ( i )
end
save.SaveSecondaryStructure ()
rb = 0
save.Quicksave ( kOriginalStructureOrNewBest )
behavior.SetClashImportance ( 1 )
if ( current.GetExplorationMultiplier () > 0 ) then
score_type = 3
end
original_slow_filters_setting = behavior.GetSlowFiltersDisabled ()
repeat
dialog_code = GetParameters ()
if ( dialog_code == 2 ) then
GetOptionalParameters ()
end
until ( dialog_code < 2 )
if ( dialog_code == 0 ) then
return
end
print ( "Loop rebuild 8.0" )
best_score = GetScore ()
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
PrintParameters ()
start_time = os.time ()
if ( keep_bands == false ) then
band.DisableAll ()
end
GetListOfFixedResidues ()
if ( mutate_not_shake == true ) then
for i = 1 , n_residues do
original_residues [ i ] = structure.GetAminoAcid ( i )
end
end
while true do
RebuildAllAtSpecifiedLength ( rebuild_length )
end
save.Quickload ( kOriginalStructureOrNewBest )
if ( keep_bands == false ) then
band.EnableAll ()
end
end
function cleanup ()
print ( "Cleaning up" )
behavior.SetClashImportance ( 1.0 )
save.Quickload ( kOriginalStructureOrNewBest )
if ( convert_to_loop == true ) then
save.LoadSecondaryStructure ()
end
selection.SelectAll ()
if ( keep_bands == false ) then
band.EnableAll ()
end
behavior.SetSlowFiltersDisabled ( original_slow_filters_setting )
end_time = os.time ()
print ( "Elapsed time : " .. os.difftime ( end_time , start_time ) .. " secs" )
if ( #loss_from_low_ci_wiggle > 1 ) then
table.sort ( loss_from_low_ci_wiggle )
mid_pt = math.ceil ( #loss_from_low_ci_wiggle / 2 )
print ( "Median loss from low ci (" .. kLowCiWiggle .. ") wiggle " .. r3 ( loss_from_low_ci_wiggle [ mid_pt ] ) )
end
if ( mutate_not_shake == true ) then
for i = 1 , n_residues do
new_residues [ i ] = structure.GetAminoAcid ( i )
end
for i = 1 , n_residues do
if ( new_residues [ i ] ~= original_residues [ i ] ) then
print ( i .. " : " .. aa1_to_aa3 ( original_residues [ i ] ) .. " -> " .. aa1_to_aa3 ( new_residues [ i ] ) )
end
end
end
end
--main ()
xpcall ( main , cleanup )