Profile


Name
Jolter 2.0
ID
101947
Shared with
Public
Parent
None
Children
Created on
March 12, 2016 at 20:30 PM UTC
Updated on
March 12, 2016 at 20:30 PM UTC
Description

See first comment

Best for


Code


best_score = 0 min_residue = 0 max_residue = 0 n_residues = 0 post_rebuild = 3 score_type = 1 original_slow_filters_setting = 0 kCurrBaseStructure = 1 curr_base_score = 0 kBestPostRebuild = 2 kTemp = 3 n_rebuilds = 4 max_loss_threshold = 5 kMaxSphereDistance = 14 SphereSegList = {} -- store list of residues within kMaxSphereDistance of any residue in the segment. -- speeds things up when shaking -- SS info ss_starts = {} ss_ends = {} ss_types = {} helix_spacer = 3 sheet_spacer = 2 loop_spacer = 1 use_helices = true use_sheets = true use_loops = true kMinSSLength = 3 -- Performance monitoring post_sw_gains = {} post_sw_threshold = 200 post_sw_skipped = 0 total_actions = 0 start_time = 0 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 behavior.SetFiltersDisabled ( false ) score = current.GetScore () behavior.SetFiltersDisabled ( 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 GetSecondaryStructures () curr_s_type = false for i = 1, n_residues do s_type = structure.GetSecondaryStructure ( i ) if ( i == 1 ) then ss_starts [ 1 ] = i ss_types [ 1 ] = s_type elseif ( s_type ~= prev_s_type ) then ss_ends [ #ss_ends + 1 ] = i - 1 ss_starts [ #ss_starts + 1 ] = i ss_types [ #ss_types + 1 ] = s_type end prev_s_type = s_type end ss_ends [ #ss_ends + 1 ] = n_residues end function SelectSphere () selection.DeselectAll () for i = 1 , n_residues do if ( SphereSegList [ i ] == true ) then selection.Select ( i ) end end end function ConstructListOfResiduesWithinRange ( start_idx , end_idx ) for i = 1 , n_residues do SphereSegList [ i ] = false end for j = start_idx , end_idx do for i = 1 , n_residues do if ( ( i >= start_idx and i <= end_idx ) or ( structure.GetDistance ( i , j ) < kMaxSphereDistance ) ) then SphereSegList [ i ] = true end end 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 structure.WiggleSelected ( 12 ) score = GetScore () if ( score < c_score ) then save.Quickload ( kTemp ) end end function NudgeWiggle () score_in_kTemp = GetScore () save.Quicksave ( kTemp) behavior.SetClashImportance ( 0.3 ) structure.WiggleSelected ( 1 ) behavior.SetClashImportance ( 1 ) structure.WiggleSelected ( 6 ) score = GetScore () if ( score < score_in_kTemp ) then save.Quickload ( kTemp ) end end function Rebuild ( start_idx , end_idx ) local score_before_sm = 0 ConstructListOfResiduesWithinRange ( start_idx , end_idx ) best_post_rebuild_score = -999999 good_rebuild_found = false i = 1 while ( i <= n_rebuilds ) do total_actions = total_actions + 1 save.Quickload ( kCurrBaseStructure ) selection.DeselectAll () selection.SelectRange ( start_idx , end_idx ) structure.RebuildSelected ( 1 ) SelectSphere () structure.ShakeSidechainsSelected ( 1 ) if ( post_rebuild >= 2 ) then -- selection.SelectAll () score_before_wiggle = GetScore () structure.WiggleSelected ( 10 ) score_after_wiggle = GetScore () if ( post_rebuild >= 3 ) then score_before_sm = GetScore () if ( curr_base_score - score_before_sm < post_sw_threshold ) then good_rebuild_found = true SelectSphere () if ( post_rebuild == 3 ) then structure.ShakeSidechainsSelected ( 1 ) else structure.MutateSidechainsSelected ( 1 ) end score_after_sm = GetScore () if ( score_after_sm - score_before_sm > 1e-3 ) then structure.WiggleSelected ( 10 ) end if ( GetScore () > curr_base_score - max_loss_threshold ) then table.insert ( post_sw_gains , curr_base_score - score_before_sm ) end else post_sw_skipped = post_sw_skipped + 1 end end -- ( post_rebuild >= 3 ) end -- ( post_rebuild >= 2 ) score = GetScore () if ( score > best_post_rebuild_score ) then best_post_rebuild_score = score save.Quicksave ( kBestPostRebuild ) end i = i + 1 end if ( ( post_rebuild >= 3 ) and ( good_rebuild_found == false ) ) then return end if ( post_rebuild >= 3 ) then save.Quickload ( kBestPostRebuild ) NudgeWiggle () best_post_rebuild_score = GetScore () save.Quicksave( kBestPostRebuild ) end if ( best_post_rebuild_score > curr_base_score - max_loss_threshold ) then save.Quickload ( kBestPostRebuild ) FinalIdealize ( best_post_rebuild_score , start_idx , end_idx ) score_after_idealize = GetScore () --print ( "Gain from idealize " .. r3 ( score_after_idealize - best_post_rebuild_score ) ) save.Quicksave ( kCurrBaseStructure ) curr_base_score = score_after_idealize print ( " new working score " .. r3 ( curr_base_score ) ) end end function Go () for j = 1 , 2 do for i = j , #ss_starts , 2 do start_idx = ss_starts [ i ] end_idx = ss_ends [ i ] print ( "rb " .. start_idx .. "-" .. end_idx .. " (" .. ss_types [ i ] .. ")" ) Rebuild ( start_idx , end_idx ) end end end function AddSpacers () for i = 1 , #ss_starts do start_idx = ss_starts [ i ] end_idx = ss_ends [ i ] if ( ss_types [ i ] == "H" ) then start_idx = start_idx - helix_spacer end_idx = end_idx + helix_spacer elseif ( ss_types [ i ] == "E" ) then start_idx = start_idx - sheet_spacer end_idx = end_idx + sheet_spacer elseif ( ss_types [ i ] == "L" ) then start_idx = start_idx - loop_spacer end_idx = end_idx + loop_spacer end ss_starts [ i ] = math.max ( 1 , start_idx ) ss_ends [ i ] = math.min ( n_residues , end_idx ) end end function BackboneFrozen ( start_idx , end_idx ) for i = start_idx , end_idx do seg_backbone_frozen, seg_sidechain_frozen = freeze.IsFrozen ( i ) if ( seg_backbone_frozen == true ) then return 1 end end return 0 end function FilterSS () -- Delete any Secondary structures that are outside the range, locked, or consist of small loops for i = #ss_types , 1 , -1 do if ( ( ss_starts [ i ] > max_residue ) or ( ss_ends [ i ] < min_residue ) or ( BackboneFrozen ( ss_starts [ i ] , ss_ends [ i ] ) == 1 ) or ( ss_types [ i ] == "H" and use_helices == false ) or ( ss_types [ i ] == "E" and use_sheets == false ) or ( ss_types [ i ] == "L" and use_loops == false ) or ( ss_ends [ i ] - ss_starts [ i ] + 1 < kMinSSLength ) ) then table.remove ( ss_starts , i ) table.remove ( ss_ends , i ) table.remove ( ss_types , i ) end end end function PrintParameters () print ( "Range " .. min_residue .. " to " .. max_residue ) print ( "N rebuilds " .. n_rebuilds ) print ( "Post sw threshold " .. r3 ( post_sw_threshold ) ) print ( "Rejection threshold " .. r3 ( max_loss_threshold ) ) print ( "Rebuild helices " .. tostring ( use_helices ) ) if ( use_helices == true ) then print ( "Helix spacer " .. helix_spacer ) end print ( "Rebuild sheets " .. tostring ( use_sheets ) ) if ( use_sheets == true ) then print ( "Sheet spacer " .. sheet_spacer ) end print ( "Rebuild loops " .. tostring ( use_loops ) ) if ( use_loops == true ) then print ( "Loop spacer " .. loop_spacer ) end if ( post_rebuild == 1 ) then print ( "Post rebuild : Shake" ) elseif ( post_rebuild == 2 ) then print ( "Post rebuild : Shake/Wiggle" ) elseif ( post_rebuild == 3 ) then print ( "Post rebuild : Shake/Wiggle/Shake/Wiggle" ) elseif ( post_rebuild == 4 ) then print ( "Post rebuild : Shake/Wiggle/Mutate/Wiggle" ) end if ( score_type == 1 ) then print ( "Score type : Normal" ) elseif ( score_type == 2 ) then print ( "Score type : Normal/Slow Filters" ) end print () end function GetParameters () local dlog = dialog.CreateDialog ( "Jolter 2,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.n_rebuilds= dialog.AddSlider ( "N Rebuilds" , n_rebuilds , 1 , 20 , 0 ) if ( IsPuzzleMutable () == true ) then post_rebuild = 4 else post_rebuild = 3 end dlog.post_rebuild = dialog.AddSlider ( "Post rebuild" , post_rebuild , 1 , 4 , 0 ) dlog.pr = dialog.AddLabel ( "1 = Sh : 2 = Sh/W : 3 = Sh/W/Sh/W : 4 = Sh/W/Mu/W" ) dlog.post_sw_threshold = dialog.AddSlider ( "Post sw threshold" , post_sw_threshold , 10 , 1000 , 0 ) dlog.max_loss_threshold = dialog.AddSlider ( "Maximum loss" , max_loss_threshold , 0 , 50 , 0 ) dlog.use_helix = dialog.AddCheckbox ( "Rebuild helices" , use_helices ) dlog.helix_spacer = dialog.AddSlider ( "Helix spacer" , helix_spacer , 0 , 4 , 0 ) dlog.use_sheet = dialog.AddCheckbox ( "Rebuild sheets" , use_sheets ) dlog.sheet_spacer = dialog.AddSlider ( "Sheet spacer" , sheet_spacer , 0 , 4 , 0 ) dlog.use_loop = dialog.AddCheckbox ( "Rebuild loops" , use_loops ) dlog.loop_spacer = dialog.AddSlider ( "Loop spacer" , loop_spacer , 0 , 4 , 0 ) if ( DoesPuzzleHaveSlowFilters () == true ) then score_type = 2 else score_type = 1 end dlog.score_type = dialog.AddSlider ( "Score type" , score_type , 1 , 2 , 0 ) dlog.tp = dialog.AddLabel ( "1 = Normal : 2 = Normal for Filters" ) dlog.ok = dialog.AddButton ( "OK" , 1 ) dlog.cancel = dialog.AddButton ( "Cancel" , 0 ) if ( dialog.Show ( dlog ) > 0 ) then min_residue = dlog.min_residue.value max_residue = dlog.max_residue.value n_rebuilds = dlog.n_rebuilds.value post_rebuild = dlog.post_rebuild.value post_sw_threshold = dlog. post_sw_threshold.value max_loss_threshold = dlog.max_loss_threshold.value use_helices = dlog.use_helix.value helix_spacer = dlog.helix_spacer.value use_sheets = dlog.use_sheet.value sheet_spacer = dlog.sheet_spacer.value use_loops = dlog.use_loop.value loop_spacer = dlog.loop_spacer.value score_type = dlog.score_type.value return true else return false end end function main () print ( "Jolter 2.0" ) n_residues = structure.GetCount () save.Quicksave ( kCurrBaseStructure ) curr_base_score = GetScore () print ( "Start score " .. r3 ( curr_base_score ) ) behavior.SetClashImportance ( 1 ) original_slow_filters_setting = behavior.GetSlowFiltersDisabled () if ( GetParameters () == false ) then return end max_residue = math.min ( n_residues , max_residue ) min_residue = math.max ( 1 , min_residue ) if ( max_residue < min_residue ) then print ( "Range error." ) print ( "Max residue (" .. max_residue .. ") must be greater than or equal to Min residue (" .. min_residue .. ")" ) return end PrintParameters () GetSecondaryStructures () AddSpacers () FilterSS () start_time = os.time () while true do Go () end end function cleanup () print ( "Cleaning up" ) behavior.SetClashImportance ( 1.0 ) save.Quickload ( kCurrBaseStructure ) end_time = os.time () print ( "Elapsed time : " .. os.difftime ( end_time , start_time ) .. " secs" ) if ( score_type == 2 ) then behavior.SetSlowFiltersDisabled ( original_slow_filters_setting ) end print () print ( "Post sw performance data" ) if ( #post_sw_gains > 0 ) then table.sort ( post_sw_gains ) mid_pt = math.ceil ( #post_sw_gains / 2 ) print ( "Median gain from working post_sw " .. r3 ( post_sw_gains [ mid_pt ] ) ) print ( "Best gains from working post_sw " ) for i = #post_sw_gains , math.max ( 1 , #post_sw_gains - 5 ) , -1 do print ( r3 ( post_sw_gains [ i ] ) ) end end print ( "Post sw skipped " .. post_sw_skipped .. "/" .. total_actions ) print () end --main () xpcall ( main , cleanup )

Comments


spvincent Lv 1

Jolter is a rebuild script that's designed, as the name suggests, to jolt the protein out of a local minimum (that's the intent anyway), although it does seem very useful as a general purpose rebuild script to use in the middle game.

It successively rebuilds alternate structural elements in the protein, being prepared to accept a small loss in score after the usual quota of shakes and wiggles that normally follow a rebuild (gains are also accepted, needless to say).

The script never terminates: it's best run overnight or at least for a couple of hours. After cancelling the script you can start from the existing position, or, since the score meanders up and down when running the script, reset best.

Algorithm outline

Get list of secondary structure elements (helix, sheet, loop)

For each element (going alternately)
Repeat 4 times (default value of N rebuilds below)
Rebuild element
Shake/Wiggle etc (Post Rebuild below)
end

Take best scoring position from above
Wiggle at low CI/wiggle
If score is better than the current score minus the rejection threshold then
make this the new current position
end

end

Min residue: max residue

Used to define the region of the protein to be rebuilt. Any secondary structure element that lies at least partially within this region will be processed.

Additionally, an element that contains a residue with a frozen backbone will not be processed.

Further control over which elements are to be rebuilt is provided by the Rebuild helices (etc) checkboxes below.

N Rebuilds

How many times to rebuild each structure. Reducing this value may result in a more structurally diverse result, albeit at the likely expense of a poorer score.

Post Rebuild

The actions to be taken after each rebuild, The default value for non-design puzzles is (Shake/Wiggle/Shake/Wiggle) but for design puzzles number the default action is (Shake/Wiggle/Mutate/Wiggle).

Rejection threshold

This is an optimization to prevent unnecessary processing being done subsequent to rebuilds which are clearly going nowhere. If Post Rebuild above is set to either of the last two positions, then, after the first Shake/Wiggle, further processing is only done if the score is lower than that of the current starting pose by less than the Rejection Threshold.

The default value of 200 works quite well but at script termination, some performance data is printed out to aid in determining a good value for this parameter. Of the rebuilds that were processed (i.e.passed this threshold test), the best gains from the subsequent Shake (or Mutate)/ Wiggle are printed. If these values are close to the rejection threshold, then the threshold should probably be increases: on the other hand if they are all much lower the rejection threshold can probably be safely reduced.

Maximum loss

Specifies how big a loss in score is permissible. The larger the value the greater the change in structure that will be allowed at the possible expense of score.

Setting this to zero means that only gains will be permitted.

Rebuild helices, Rebuild sheets, Rebuild loops

Control over which structural elements to rebuild

Helix spacer, Sheet spacer, Loop spacer

When rebuilding, specifies the length of a spacer at either end of the structural element that will be included in the rebuild. So if the value of Helix spacer were 3, then when working on a helix from 63 to 75, the actual rebuild length would be 60 to 78.

Score type

If set to 2, toggles filters off except when determining the score. For better performance on slow design puzzles.

gitwut Lv 1

Yes, Stephen mentions that it accepts lowered scores (you can control acceptable losses via slider at start of the script). It backtracks when attempting to break out of a minimum.

Bruno Kestemont Lv 1

I made a private 2.1 version only by allowing gain in the "accepted loss" slider.

The gain (negative loss) works like a minimum point per iteration: it saves moves, which is great for sketchbox puzzles.

I suggest you to make an official 2.1 or 2.0.1 version like this.