Icon representing a recipe

Recipe: Loop rebuild 6.0

created by spvincent

Profile


Name
Loop rebuild 6.0
ID
100669
Shared with
Public
Parent
None
Children
None
Created on
February 07, 2015 at 20:12 PM UTC
Updated on
February 07, 2015 at 20:12 PM UTC
Description

See first comment

Best for


Code


-- Copyright notice. -- You may copy and paste at will. Plagiarize shamelessly! -- End copyright notice -- Changes since 5.2 -- 1) Added threshold parameters -- 2) Removed performance monitoring : it was cluttering up the code too much. -- 3) Added different score types -- 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. 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 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 = {} kInnerSphereRadius = 10 kOuterSphereRadius = 18 kDefaultWiggleDuration = 12 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 -- 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 = 0 -- For design mutate_not_shake = false -- 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 = 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 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 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 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 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 ( 0.2 ) structure.WiggleSelected ( 1 ) 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 ) save.Quickload ( kBestPostRebuild_b ) structure.WiggleSelected ( kDefaultWiggleDuration ) score_b = GetScore () if ( score_a > score_b ) then save.Quickload ( kBestPostRebuild_a_post_wiggle ) end end function PostWiggle () init_score = GetScore () save.Quicksave ( kTemp ) if ( score_type == 4 or score_type == 5 ) 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 (tweak able 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 ) then return 1 -- Hiding or bonding elseif ( score_below_best < post_rebuild_threshold ) then ShakeLowCIWiggle ( init_score ) return 1 else return 0 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 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 ( 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 if ( good_rebuild_found == true ) then 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 candidate_section_found = true rb = rb + 1 print ( "rb ".. rb .. " " .. start_idx .."-" .. end_idx .. " (" ..i .. "/" .. n_possible_segs .. ")" ) if ( RebuildSeg ( start_idx , end_idx ) == 1 ) then SelectOuterSphere () WiggleTwoBestCandidatesAndSelectBest () score_after_bc_wiggle = GetScore () if ( PostWiggle () == 1 ) then score_after_post_wiggle = GetScore () if ( FinalFuse ( start_idx , end_idx ) == 1 ) then score_after_final_fuse = GetScore () 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 ( "Issue with section " .. start_idx .."-" .. end_idx ) 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 6.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.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 ( "__________________________________________" ) design_puzzle = IsPuzzleMutable () if ( design_puzzle == true ) then dlog.mutate= dialog.AddCheckbox ( "Mutate" , true ) end dlog.pw_threshold = dialog.AddSlider ( "Post wiggle threshold" , pw_threshold_value , 0 , 200 , 0 ) if ( DoesPuzzleHaveSlowFilters () == true ) then score_type = 6 end dlog.score_type = dialog.AddSlider ( "Score type" , score_type , 1 , 6 , 0 ) dlog.tp = dialog.AddLabel ( "1 = Normal : 2 = Energy : 3 = Explore : 4 = Hiding" ) dlog.tp_2 = dialog.AddLabel ( "5 = Bonding : 6 = 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 ) 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 if ( design_puzzle == true ) then mutate_not_shake = dlog.mutate.value end pw_threshold_value = dlog. pw_threshold.value score_type = dlog.score_type.value test_for_credit = dlog.credit_check.value return true else return false end end function main() band.DisableAll () 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 () if ( GetParameters () == false ) then return -- graceful exit end print ( "Loop rebuild 6.0" ) best_score = GetScore () 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 : Normal/Slow Filters" ) end 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 start_time = os.time () 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 () 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 ) if ( convert_to_loop == true ) then save.LoadSecondaryStructure () end selection.SelectAll () band.EnableAll () behavior.SetSlowFiltersDisabled ( original_slow_filters_setting ) end_time = os.time () print ( "Elapsed time : " .. os.difftime ( end_time , start_time ) .. " secs" ) end --main () xpcall ( main , cleanup )

Comments


spvincent Lv 1

Changes since 5.0

Quite a few but two significant ones, designed to speed things up, particularly on design puzzles.

a) Removed the terminal wiggle in the Rebuild/Shake/Wiggle Loop.
b) Added a scoring mode (number 6) for puzzles with Slow Filters. When in this mode, Slow filters are mostly disabled but toggled on when determining the score.

For Design and Symmetry puzzles, drag the Score Type slider to the right so its at it's maximum value of 6: this will happen by default if it looks like the current puzzle has Slow Filters.


Given a number of rebuilds, which is the best one to use? Not necessarily the best-scoring one, or even the best-scoring one at low CI (see http://proteinoftheday.wordpress.com ), but probably the best-scoring after shake and, which is what's going on here. Since Shake and Wiggle are computationally expensive, some effort is made to work only with the relevant sub-section of the protein.

Can be used at any Wiggle Power.

Algorithm outline


For each section to rebuild
   For each rebuild (defined by N Rebuilds)
      Rebuild once
      Set selection to that defined by Inner sphere
      Shake
   end
   
   For each pose corresponding to the two best scores above
      Set selection to that defined by Outer sphere
      Wiggle
   end

   Take the best pose from the two above
   Set selection to that defined by Outer sphere
   Shake (or Mutate if a design puzzle and that option chosen)
   Wiggle again if the Shake or Mutate gained anything.

   If we've gained an overall improvement
      Shake at low CI
      Wiggle at normal CI
      Record overall improvement
  end

end

Dialog settings

Rebuild Length

How big a section to rebuild. Values from 4 to 6 are typically most useful, but larger values are valuable

Min residue, Max residue

Only rebuild sections that lie within this range: by default the entire protein can be used. These values can be usefully changed to whatever region of the protein you're working on: it's often desirable to set them to the start and end of a loop you're working on.

Loops only

When set, only loops will be rebuilt, although a single non-loop residue is allowed. This effectively means that the end residue of a helix or sheet will be treated as a loop for rebuild purposes.

Convert to Loops

Meaningful if and only if Loops only above is unchecked. If checked, non-loops will be converted to loops before rebuilding: if not the secondary structure will be maintained.

So for example, if you had a helix from 35-40 and you wished to rebuild it as a helix with, say , a loop spacer 2 residues wide on either end, suitable settings would be:

Rebuild Length 10
Min residue 33
Max residue 42
Loops only unchecked
Convert to loops unchecked

N rebuilds

How many rebuilds to attempt. The default is a bit of a compromise: too small a value means that not enough poses will be created: too many and there's a high probability of ending up working on a pose which is extremely similar to the starting structure.

Mutate not shake

This checkbox will appear if and only if the puzzle contains mutable residues. If set (default), the sidechain shake in the algorithm will be replaced by a mutate.

Post wiggle threshold

An optimization used to prevent doing unnecessary shake/mutates. If the score after the best rebuild/shake (as described in the algorithm) is below the best by more than this amount, then skip the subsequent fuze-like processing as an overall gain is unlikely,

The default value works quite well: it might be worth lowering it to say 10 for endgame running or raising it to 60 or so at the beginning, particular for symmetry puzzles where overall scores are greater than usual.

Score type

Allows different scoring functions to be used - the values are:

1) Normal. Self-explanatory: the value as described by the program. Most of the time this is what you'll want

2) Exploration score. Perhaps one day there will be another exploration puzzle.

3) Energy score. Design puzzles without those filters.

4) Hiding. Just use the hiding component of the score.

5) Bonding. Just use the bonding component of the score.

In the last two cases, no fuzing will be done, irrespective of the threshold value.

6) As explained above: Toggles Slow Filters apart from scoring.

Check conditions met:

If set, check that conditions are met before accepting any improvement. For puzzles with RMSD conditions, etc.