Icon representing a recipe

Recipe: Glycine Hinge v2.4.1

created by KarenCH

Profile


Name
Glycine Hinge v2.4.1
ID
100513
Shared with
Public
Parent
Glycine Hinge v2.4
Children
Created on
January 04, 2015 at 22:17 PM UTC
Updated on
January 04, 2015 at 22:17 PM UTC
Description

Glycine Hinge with better choices -- variable width hinges and band-strength

Best for


Code


--[[------------------------------------------------------------------------------------------------ Glycine hinge v1.3.0.0 -- Because Glycine is the most flexible Amino acid, it will respond readily and rather predictably to manipulation. The "glycine hinge" is a tactic used to shape a section of a Loop containing at least one glycine. It is most useful when a player has some idea of where other secondary structures should go, and wants to bend the loop in a way that will put them in the appropriate places while not dragging down his local score too much.[1] The recipe attempts to freeze backbone, and necessary Secondary Structures (SS), ("The rods"), around the surrounding Glycine Amino Acid (AA), ("The hinge"), and proceeds to wiggle with bands. Copyright (C) 2011 tlaloc <http://fold.it/portal/user/57765> Copyright (C) 2011 rav3n_pl <http://fold.it/portal/user/174969> Copyright (C) 2011 Seagat2011 <http://fold.it/port/user/1992490> Copyright (C) 2011 thom001 <http://fold.it/port/user/172510> Heavily rewritten by KarenCH (August 2014) -------------------------------------- REFERENCES -------------------------------------- 1. - "Glycine Hinge" - http://foldit.wikia.com/wiki/Glycine_Hinge ------------------------------------------------------------------------------------------------]]-- USENORMALSCORE = true -- exploration puzzles would set false DEBUGRUN = true -- mostly goes with DebugPrint, but could get more use later GH_BAND_DEFAULT_STRENGTH = 0.25 QS_Start = 1 QS_Best = 3 EndCalled = false segCt = structure.GetCount() CurrentBestScore = 0.0 InitialScore = 0.0 InitialTime = 0 local UserOptions = { hingeWidth = 1, -- number of unfrozen segments to do hinging around glycineIdxList = {}, hingeStartIndices = {}, hingeEndIndices = {} } local function FindAllGlycines( options ) for idx = 1, segCt do if structure.GetAminoAcid( idx ) == 'g' then options.glycineIdxList[ #options.glycineIdxList + 1 ] = idx end end end local function GetEndOfRod( startIdx, doForward ) local tmp = structure.GetSecondaryStructure(startIdx ) endIdx = startIdx if endIdx <= 1 or startIdx >= segCt then return startIdx end while ( 1 ) do if tmp == structure.GetSecondaryStructure( endIdx ) then if doForward then if endIdx < segCt then endIdx = endIdx + 1 else endIdx = segCt break end else if endIdx > 1 then endIdx = endIdx - 1 else endIdx = 1 break end end else if doForward then endIdx = endIdx - 1 else endIdx = endIdx + 1 end break end end -- while ( 1 ) return endIdx end function PerformHinge( startHinge, endHinge ) if startHinge > endHinge then startHinge, endHinge = endHinge, startHinge end DebugPrint( "Hinge is from "..startHinge.." to "..endHinge ) if startHinge <= 2 or endHinge >= segCt-1 then print( "Cannot build hinge - too close to end" ) return false end -- find bounds of rods startLeftRod = GetEndOfRod( startHinge - 1, false ) endRightRod = GetEndOfRod( endHinge + 1, true ) DebugPrint( "LeftRod: "..startLeftRod.." to ".. startHinge-1 .. " RightRod: ".. (endHinge+1) .." to "..endRightRod ) SaveBest( ) -- freeze the "rods" selection.DeselectAll () selection.SelectRange( endHinge + 1, endRightRod ) selection.SelectRange( startLeftRod, startHinge - 1 ) freeze.FreezeSelected( true, false ) selection.DeselectAll () -- put bands between the rods for i = 1,4 do local n1 = startHinge - i local n2 = endHinge + i if n1 >= 1 and n2 <= segCt then local bIdx = band.AddBetweenSegments( n1, n2 ) band.SetStrength( bIdx, GH_BAND_DEFAULT_STRENGTH ) end end -- perform glycine hinge's version of a banded wiggle recentbest.Save( ) ExactSetCI( 0.30 ) structure.WiggleAll( 1 ) DelBands( ) ExactSetCI( 1.00 ) structure.WiggleAll( 30 ) recentbest.Restore( ) DelBands( ) -- because recentbest might restore them freeze.UnfreezeAll( ) SaveBest( ) end function PerformHingeSequence( options ) for i=1, #options.hingeStartIndices do local gain = 0.0 local currScore = getScore( ) repeat LoadBest( ) PerformHinge( options.hingeStartIndices[ i ], options.hingeEndIndices[ i ] ) PrintState( ) local newScore = getScore( ) gain = newScore - currScore currScore = newScore until TrimNum( gain ) == 0.0 end -- FOR (i) end local function GetUserParams( options ) print( "Give comma separated list" ) print( "Indicate ranges to hinge around by '#-#' " ) local glystr = "" for i=1, #options.glycineIdxList do if i > 1 then glystr = glystr .. ", " end glystr = glystr .. options.glycineIdxList[ i ] end dlg = dialog.CreateDialog( "------------- Glycine Hinge -------------" ) dlg.ghcmt1 = dialog.AddLabel( "Glycines: "..glystr ) dlg.ghcmt2 = dialog.AddLabel( "Comma sep list; ranges use -" ) dlg.idxset = dialog.AddTextbox( "Hinges", tostring( options.glycineIdxList[ 1 ] ) ) dlg.bandstrength = dialog.AddSlider( "Band strength", GH_BAND_DEFAULT_STRENGTH, 0.01, 1.50, 2 ) dlg.ok = dialog.AddButton( "OK", 1 ) dlg.cancel = dialog.AddButton( "Cancel", 0 ) if dialog.Show( dlg ) > 0 then GH_BAND_DEFAULT_STRENGTH = dlg.bandstrength.value -- fancy parsing here: Input format is: idx1,idx2-idx3,idx4,idx5,idx6-idx7 options.hingeStartIndices = {} options.hingeEndIndices = {} for w in string.gmatch( dlg.idxset.value, "[^,]+" ) do if string.find( w, "-" ) ~= nil then local f, s = string.match( w, "(%d+)%-(%d+)" ) options.hingeStartIndices[ #options.hingeStartIndices + 1] = tonumber( f ) options.hingeEndIndices[ #options.hingeEndIndices + 1] = tonumber( s ) else options.hingeStartIndices[ #options.hingeStartIndices + 1] = tonumber( w ) options.hingeEndIndices[ #options.hingeEndIndices + 1] = tonumber( w ) end end return true end return false end ---------------------------------------------------------------- -- ---------------- BOILERPLATE --------------------- -- ---------------------------------------------------------------- function DebugPrint( str ) if DEBUGRUN then print( str ) end end function BoolStr( bval ) if bval then return "true" end return "false" end function TrimNum( val ) return val - val % 0.001 end -- Not for "external" use - call getScore. This could change if customers want -- something besides current or recentbest. function internalGetScore( wantRB ) if wantRB == nil then wantRB = false end local s=0.0 if not USENORMALSCORE then if wantRB then s = recentbest.GetEnergyScore( ) else s=current.GetEnergyScore( ) end else if wantRB then s = recentbest.GetScore( ) else s=current.GetScore( ) end end return s end function getScore( ) return internalGetScore( false ) end function getRBScore( ) return internalGetScore( true ) end function SaveBest( ) local score = getScore( ) if score > CurrentBestScore then save.Quicksave( QS_Best ) CurrentBestScore = score end end function LoadBest( ) save.Quickload( QS_Best ) end function SetCI( ci ) behavior.SetClashImportance( SCALE_MAXCI * ci ) end function ExactSetCI( ci ) behavior.SetClashImportance( ci ) end function DelBands() band.DeleteAll() end ----------------------- MATHY STUFF ----------------------- function seedRandom() seed=os.time( )/math.abs( getScore( ) ) seed=seed%0.001 seed=1/seed while seed<10000000 do seed=seed*1000 end seed=seed-seed%1 DebugPrint( "Seed is: "..seed ) math.randomseed( seed ) -- throw away a couple of randoms math.random( ) math.random( ) end function random( n1,n2, forceFloat ) --random function returns int or float depends on input vars if forceFloat == nil then forceFloat = false end if n1==nil then return math.random() else if n2==nil then if n1 == 0 then return 0 end -- a random number between 0 and 0 is 0 if n1%1==0 then -- can't test for "forceFloat", so caller must beware return math.random( n1) --integer else return math.random( ) * n1 --float end else if n1%1==0 and n2%1==0 and not forceFloat then return math.random( n1, n2 ) --integer between else return math.random( ) * (n2 - n1) + n1 --float between end end end end -------------------------------------------------------------------------- -- SETUP and CLEANUP -------------------------------------------------------------------------- function PrintState( ) local gain = getScore() - InitialScore if gain < 0.001 then print( " No change" ) else print( " Startscore: "..TrimNum( InitialScore )) print( " Score: "..TrimNum( getScore() ) ) print( " Total gain: "..TrimNum( gain )) end print( " Run time: "..os.time() - StartTime) end function End( errstr ) if EndCalled then return end -- no infinite recursion please EndCalled = true print( "" ) if errstr ~= nil then if string.find( errstr, "Cancelled" ) then print( "User cancel" ) else print( errstr ) end end ExactSetCI( InitialClashImportance ) LoadBest( ) PrintState( ) print("") end function InitializePuzzleState( ) seedRandom() InitialScore = getScore( ) CurrentBestScore = InitialScore StartTime = os.time() save.Quicksave( QS_Start ) save.Quicksave( QS_Best ) InitialClashImportance = behavior.GetClashImportance() end ---------------------------------------------------------------- -- MAIN ---------------------------------------------------------------- function main() InitializePuzzleState( ) local options = UserOptions FindAllGlycines( options ) print ( "Glycine hinge - recipe" ) print( "Initial state stored in slot "..QS_Start.."; best in slot "..QS_Best ) print( "Initial score: " .. InitialScore ) if #options.glycineIdxList == 1 then print( "There is "..#options.glycineIdxList.." glycine" ) elseif #options.glycineIdxList == 0 then print( "There are no glycines" ) else print( "There are "..#options.glycineIdxList.." glycines" ) end while GetUserParams( options ) do PerformHingeSequence( options ) end -- WHILE GetUserParams End( ) end xpcall( main, End )

Comments