Icon representing a recipe

Recipe: GAB_proj_beta_v1.3.2

created by robgee

Profile


Name
GAB_proj_beta_v1.3.2
ID
104623
Shared with
Public
Parent
None
Children
None
Created on
March 12, 2021 at 22:04 PM UTC
Updated on
March 12, 2021 at 22:04 PM UTC
Description

GAB filters, dialog

Best for


Code


--GAB_proj_beta_v1.3.2 --[[ Genetic Algorithm on Bands by Rav3n_pl,CartoonVillan, Crashguard303. additional code by jeff101, Bruno Kestemont,Timo van der Laan, LociOiling ]]-- -- GAB_proj_beta_v1.3.2 -- CodeBase: Rav3n_pl GAB 2.0.6, GAB_clean_cuts d005b -- Timo filters,dialogs,some BrunoK mods,select sphere --ToDo: -- Mutate CI ? make it constant not scalable --[[ Definitions: band: randomised: start segment, end segment, length, strength critter: set of bands herd: set of critters Overview: - randomize needed bands - randomly assiging them to critters - score each critter - keep critters scoring above score - breed best critters - breed bastards ( best one + random one ) - forget about rest of critters - randomize new critters to fill herd ]]-- undo.SetUndo( false ) --2020 Bands are slow this supposedly speeds things along -- ------------------------------------ -- ---------- GLOBAL VARS ------------- -- ------------------------------------ Recipe = "GAB_proj_beta" Version = "v1.3.2" ReVersion = Recipe .. " " .. Version -- -- -- ------------- OPTIONS -------------- -- -- ShakMutRadius = 8 -- radius for select sphere SmallMutate = false -- works for both shake and mutateOnce -selects sphere of segmnets pullCI = 0.9 -- Clash Importance during pull shakeCI = 0.21 -- CI when shake on qstab or mutate once noQstab = true -- extra wiggle(0.4ci) and shake(1ci) noFuze = true fuzeThresh = 20 -- run fuze if we gain this many points or more --qstabThresh = 1 -- run qstab if score drops more than x pts onlyMutable = false -- if true use ONLY all mutable aas, overrides AlwaysUse - applies to ONE end of band only mutateOnce = false -- if true do mutate( 1 ) after banded wiggle mutateCI = 0.75 -- mutate on what clashing importance mutateAlways = false -- if true use mutate( 1 ) instead of shake --no shake, no CI, if fuze then mutates everything x2 !!! herd = --herd options { breedBest = 4, -- breed best 4 critters - all combinations = > 6 kids form 4 critters, 3 form 3, 1 form 2, 9 form 5 ;] -- ????? keepBest = 2, -- save up to n best scoring critters, rest are forgotten breedBastards = 8, -- number of best will have one random bastard newRandom = 6, -- adding new random ones each generation maxGen = 20, -- maximum generations shuffle = true, -- set true to run critters in random order renew = 2, -- create COMPLETELY NEW herd after that many gens w/o improvement } critter = --critter options { minBands = 3, -- minimum bands maxBands = 7, -- maximum bands keepScore = 0 , -- survive to next gen only if score higher than breedScore = -20, -- will breed kids only if score higher. Bastards always breed maxLoss = 30, -- maximum loss by critter. set 0 to disable -- hows this work ??? } bands = --bands options { minStr = 0.3, -- minimum band str maxStr = 1.1, -- maximum band str minChng = 3, -- minimum change of band len accordig to current distance maxUp = 6.1, -- maximum chnage up ( push ) maxDn = 6.9, -- maximum change down ( pull ) minSkip = 5, -- minimum segment distance between the from-to segments of a single band minDist = 4, -- minimum spatial distance minLen = 2, -- minimum length of created band } -- Any segs in DoNotUse will never be used . Ranges only --just patched this in; needs more elegance -- example: 1,2,3,4 = "{1,4}," DoNotUse = {--just comment lines below or add more areas to avoid --{120, 134}, --{1, 50}, } --It MAY be used ! AlwaysUse = { --areas should be always used --- applies to ONE end of band only --{236,236}--ligand need to be at one end --{308,311}, --loopy --{272,319}, --loopy } -- at least one end of all bands, will always be from this list. UseSegments = {} --use ONLY these segments for ONE end of a band, Comma Separated Values, NO ranges. -- The only difference between AlwaysUse and UseSegments that i can see is one takes ranges the other takes csv. -- They are both merged together later -- bands by secondary structure use = { Sheet = true, --set false to not band sheets Helix = true, --set false to not band helices Loop = true, --set false to not band loops } checkBoth = false --check both ends to above, if false only one end need to be true --end user options CapCI = true -- caps CI to userSetMaxCI value. false is relative CI maxCI = true -- used to flag WF value userSetMaxCI = 1 -- User set maximum CI value WF = 1 -- WiggleFactor, user set more wiggles factor band_Oligomer = true HASMUTABLE = false keep_bands = true MINGAIN = 1 SYMMETRICBANDS = false -- ------- END OPTIONS -------- -- -------- Shorts BASESCORE = current.GetEnergyScore( ) -- unfiltered startscore for reference Cut = structure.InsertCut segCnt = structure.GetCount( ) USERBANDS = band.GetCount( ) -- ------- END GLOBALS -------- --======================================== --[[ Quicksaves used: qs1 - Start pose qs2 - savebest qs4 - save recentbest qs5 - max.loss- best critter score qs98 - filter score qs99 - filter score ]]-- --========================================= DEBUGRUN = false function dbgprint( debug_msg ) --dbgmsg must be entirely string if DEBUGRUN then print( debug_msg ) end end--Thnx to KarenCH function HasLigandCheck( ) alwaysLigand = false segCnt2 = segCnt while structure.GetSecondaryStructure(segCnt2)=="M" do segCnt2 = segCnt2-1 end HASLIGAND = segCnt2 < segCnt if HASLIGAND then LIGAND = segCnt alwaysLigand = true end end function HasMutableCheck( ) HASMUTABLE = false for i = 1, segCnt do if structure.IsMutable( i ) then HASMUTABLE = true break end end end function SymCheck() local is_sym = structure.GetSymCount() if is_sym >0 then SYMMETRICBANDS = true else SYMMETRICBANDS = false end return is_sym end function Score( ) return current.GetEnergyScore( ) end --------------------------------------------- ----------------- CI STUFF ------------------ --------------------------------------------- --WF = 1 --INT, user set- more wiggles factor --wf --INT, used in wiggle function only if maxCI is true --userSetMaxCI --FLOAT, user preferred value --maxCI --BOOL, used in wiggle function -boolean flag to use WF value --CapCI --BOOL, if true cap CI to userSetMaxCI else multiply recipeCI value by userSetMaxCI --RecipeCI --FLOAT, value that recipe sets function CI( RecipeCI )-- Cap CI else relative CI if RecipeCI > 0.99 then maxCI = true else maxCI = false end local Using_CI = RecipeCI if CapCI == true then if RecipeCI > userSetMaxCI then Using_CI = userSetMaxCI end else Using_CI = RecipeCI * userSetMaxCI -- relative CI end if Using_CI < 0 or Using_CI > 1 then--sanity check print( 'CI ERROR, CI now set to 1' ) Using_CI = 1 end --print('Recipe set CI', RecipeCI, ' Using_CI ', Using_CI ) behavior.SetClashImportance( Using_CI ) end-- Thnx to TvdL --------------------------------------------- -------------- FILTER STUFF ----------------- --------------------------------------------- -- ------------ -- Module Filteractive -- First step: check if Filters are active TvdLscore = current.GetEnergyScore() behavior.SetSlowFiltersDisabled( true ) TvdLscore2 = current.GetEnergyScore() behavior.SetSlowFiltersDisabled( false ) TvdLmaxbonus = TvdLscore - TvdLscore2 function TvdLFilter() local ask=dialog.CreateDialog("Slow filters seem to be active") ask.disable=dialog.AddCheckbox("Run with disabled slow filters",TvdLFilteractive) ask.l1=dialog.AddLabel("Current bonus is: "..TvdLmaxbonus) ask.l2=dialog.AddLabel("If this is not the maximum bonus put in a number") if TvdLmaxbonus < 0 then TvdLmaxbonus=0 end ask.maxbonus=dialog.AddTextbox("Set maxbonus:",TvdLmaxbonus) ask.l3=dialog.AddLabel("Scores will only be checked for real gains if") ask.l4=dialog.AddLabel("Score with filter off+maxbonus is a potential gain") ask.continue=dialog.AddButton("Continue",1) dialog.Show(ask) TvdLmaxbonus= ask.maxbonus.value if TvdLmaxbonus == "" then TvdLmaxbonus = 0 end TvdLFilteractive=ask.disable.value end BetterRecentBest=false function FilterOff() -- Filters off but restore a better recentbest with filter off behavior.SetSlowFiltersDisabled(true) if BetterRecentBest then save.Quicksave(99) save.Quickload(98) recentbest.Save() save.Quickload(99) end end function FilterOn() -- Filter on but remember recent best if better than current BetterRecentBest= recentbest.GetEnergyScore() > current.GetEnergyScore() if BetterRecentBest then save.Quicksave(99) recentbest.Restore() save.Quicksave(98) save.Quickload(99) end behavior.SetSlowFiltersDisabled(false) end TvdLFilteractive=(math.abs(TvdLmaxbonus) > 0.1) if TvdLFilteractive then --Filters active, give people a choice --And ask what the maximum bonus is. TvdLFilter() end -- End of module Filteractive -- -- -- - -- bestScore=Score() if TvdLFilteractive then FilterOff() end function SaveBest() if (not TvdLFilteractive) or (Score() + TvdLmaxbonus > bestScore ) then if TvdLFilteractive then FilterOn() end local g = Score() - bestScore if g > MINGAIN then if g > 0.01 then print("++Gained another "..round(g).." pts.", " to:", round( Score() ) ) end bestScore = Score() save.Quicksave( 2 ) end if TvdLFilteractive then FilterOff() end --end of function-- add this filter end end function DoFuze( )-- added filter here as well if (not TvdLFilteractive) or (Score() + TvdLmaxbonus > bestScore ) then if TvdLFilteractive then FilterOn() end local g = Score() - bestScore if g > fuzeThresh and noFuze == false then FuzeWithCuts() end if TvdLFilteractive then FilterOff() end -- end of function -- add this filter end end function SaveRB( )-- added filter here as well if (not TvdLFilteractive) or (current.GetEnergyScore()+TvdLmaxbonus> bestScore) then if TvdLFilteractive then FilterOn() end local rb = 0 if energy == true then rb = recentbest.GetEnergyScore( ) else rb = recentbest.GetScore( ) end if rb > bestScore then save.Quicksave( 4 ) recentbest.Restore( ) SaveBest( ) save.Quickload( 4 ) end if TvdLFilteractive then FilterOff() end end end-- Thnx to Timo van der Laan ----------- END FILTER STUFF ----------------- ---------------------------------------------- -- ------------------------------------------- -- -------- STANDARD FUNCTIONS --------------- -- ------------------------------------------- function SelectSphere(sg, radius) --selection.DeselectAll() for i=1, segCnt do if structure.GetDistance(sg,i)<radius then selection.Select(i) end end end--TvdL -- --- -- function uncut(seg) if seg == nil then print('A nil segment is ',seg) print('uncutting all segments') for i = 1, structure.GetCount( ) do structure.DeleteCut( i ) end else --print( 'Deleting cut at seg:',seg ) structure.DeleteCut( seg ) end end -- --- -- function WigglePowerShowSettting( ) local get_wig_pow = behavior.GetWigglePower( ) local wigdict={ ["l"] = "Low", ["a"] = "Auto", ["m"] = "Medium", ["h"] = "High" } local result = wigdict[ get_wig_pow ] return result end -- --- -- function CleanUseSegments( )--add check for doubles ??? --sanity check on segnums, "never trust user input" --this really needs a minimum length what if theres only 5 segments ?? for i = #UseSegments, 1, -1 do local seg = UseSegments[i] if seg > segCnt then print( 'ERROR segment too high: removing segment', seg ) table.remove( UseSegments, i ) end end for ii = #UseSegments, 1, -1 do --table remove can change table len and indexes local seg = UseSegments[ii] if seg <= 0 then print( 'ERROR segment too low: removing segment', seg ) table.remove( UseSegments, ii ) end end print("How many residues", segCnt ) if #UseSegments ==0 then print('Random segment selection from '.. segCnt ..' segs') else print("Using this many segs", #UseSegments) end end -- ---- -- function DeleteBands( ) --add deleteeAll ?? nbands = band.GetCount( ) if nbands > USERBANDS then for i = nbands, USERBANDS + 1, -1 do -- count down from nbands to USERBANDS + 1 band.Delete( i ) end end end -- thanks to Jeff101 -- ---- -- function round( x )-- round to 3 places return x - x % 0.001 end function down( x )-- round down to 1 place return x-x % 1 end -- ---- -- function SeedRandom( ) local seed = os.time ( ) / math.abs ( current.GetEnergyScore ( ) ) seed = seed % 0.001 seed = 1 / seed while seed < 10000000 do seed = seed * 1000 end while seed > 2 ^ 32 do seed = seed / 10 end--LO seed = seed - seed % 1 math.randomseed( seed ) math.random( ); math.random( ); math.random( ) --See stackoverflow end-- Rav3n_pl, LociOiling function Randomz( n1, n2 ) --random function returns int or float depends on input vars --can return 0 if n2 == nil and n1 == nil then return math.random( ) --float else if n2 == nil then if n1%1 == 0 then return math.random( n1 ) --integer else return math.random( ) * n1 --float end else if n1%1 == 0 and n2 % 1 == 0 then return math.random( n1, n2 ) --integer between else return math.random( )*( n2-n1 ) + n1 --float between end end end end -- -- - -- function Cleanup( err ) if CLEANUPENTRY ~= nil then return end CLEANUPENTRY = true --LO print( '========================' ) print( ReVersion..' Cleaning up' ) save.Quickload( 2 )--best pose DeleteBands( ) selection.DeselectAll() print( "Base score",BASESCORE) print( "Start score: "..ss ) print( "Final score: "..Score( ) ) print( "Total gain: "..round( Score( ) - ss ) ) if TvdLFilteractive then FilterOn( ) end print( "Unfiltered score: "..current.GetEnergyScore( ) ) undo.SetUndo( true ) behavior.SetClashImportance(userSetMaxCI)--return to user setting print( err ) end -- ------- END STANDARD FUNCTIONS ----------- -- ------------------------------------------ -- ------------------------------------------ -- ------------------------------------------ --START quick shake algorithm --not sure if this is relevant anymore now 1 shake iter pretty much is it but does take a while function QuickShake() --[[--------------------------------- -- Algorithm for faster shake REFERENCES 1. N/A Copyright ( C ) 2014 Seagat2011 <http://fold.it/port/user/1992490> This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or ( at your option ) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. $Id$ --------------------------------------------------------------------------]]-- --[[ v1 - Inception 1.2 - Loops until nogain ]]-- local idx = 1 local idx2 = structure.GetCount () local hash = {} local cs = current.GetScore () --print ( 'Quick Shake Algorithm v1.2 SG2011 - Current Score: '..cs ) local function New ( obj ) return obj -- pass-new-obj-by-value end local _gses = New ( current.GetSegmentEnergySubscore ) local function SmartShake ( iters ) local gain = true while ( gain ) do gain = false for i = idx, idx2 do local ci = _gses ( i, 'clashing' ) if ci < _gses ( i, 'hiding' ) and ci < _gses ( i, 'packing' ) and ci < _gses ( i, 'ideality' ) and ci < _gses ( i, 'sidechain' ) and ci < _gses ( i, 'bonding' ) and ci < _gses ( i, 'other' ) and ci < _gses ( i, 'reference' ) then selection.Select ( i ) end -- test ci -- end -- loop -- if selection.GetCount () then local css = current.GetScore () structure.ShakeSidechainsSelected ( iters ) selection.DeselectAll () if current.GetScore () > css then gain = true end -- test -- end -- test -- end -- loopf -- end structure.SmartShake = SmartShake structure.SmartShake ( 1 ) end -- ---- END quick shake algorithm ----------- --------------------------------------------- ------------- WIGGLE FUNCTION --------------- --------------------------------------------- -- Timos edrw302 Wiggle funtion -- New WiggleFactor -- Optimized due to Susumes ideas -- Note the extra parameter to be used if only selected parts must be done function Wiggle( how, iters, minppi, onlyselected ) -- take advantage of onlyselected parameter here if how == nil then how = "wa" end if iters == nil then iters = 3 end if minppi == nil then minppi = 0.1 end if onlyselected == nil then onlyselected = false end local currentgetci = 1 local wf = 1 if maxCI then wf = WF end --if recipe CI is 1 then wiggle more --print('Wiggle factors, wf,WF:',wf,WF, 'maxCI',maxCI, 'Wiggles',(2 * wf * iters) )--debug local sp = Score() -- ------------------------------------------------------------------------------------------- if onlyselected then if how == "s" then if mutateAlways == true then currentgetci = behavior.GetClashImportance() --Note1 behavior.SetClashImportance(mutateCI) structure.MutateSidechainsSelected( 1 )-- no shake !! behavior.SetClashImportance( currentgetci ) else dbgprint('Only Selected shake') structure.ShakeSidechainsSelected( 1 ) --QuickShake() return end elseif how == "wb" then structure.WiggleSelected( 2 * wf * iters, true, false ) elseif how == "ws" then structure.WiggleSelected( 2 * wf * iters, false, true ) elseif how == "wa" then structure.WiggleSelected( 2 * wf * iters, true, true ) end else -- ------------------------------------------------------------------------------------------- if how == "s" then if mutateAlways == true then currentgetci = behavior.GetClashImportance() behavior.SetClashImportance(mutateCI) structure.MutateSidechainsAll( 1 ) behavior.SetClashImportance( currentgetci ) else --structure.ShakeSidechainsAll( 1 ) dbgprint('Selected All quickshake') --if some are slected it will shake them then recurse QuickShake() return end elseif how == "wb" then structure.WiggleAll( 2 * wf * iters, true, false ) elseif how == "ws" then structure.WiggleAll( 2 * wf * iters, false, true ) elseif how == "wa" then structure.WiggleAll( 2 * wf * iters, true, true ) end end end-- TvdL --Note1 "it is sometimes inevitable to write bad code" --this needs sorting out --Shake MutateOnce,MutateAlways the logic is all twisted together -- --------- END WIGGLE FUNCTION ------------- -- ------------------------------------------- -- ------------------------------------------- --------------------------------------------- --------------- FUZES ----------------------- --------------------------------------------- function FuzeEnd( ) CI( 1 ) Wiggle( "wa", 1 ) Wiggle( "s", 1 )--mutateAlways and all are selected Wiggle( ) srb( ) end function Fuze1( ci1, ci2 ) CI( ci1 ) Wiggle( "s", 1 )--mutateAlways CI( ci2 ) Wiggle( "wa", 1 ) end function Fuze2( ci1, ci2 ) CI( ci1 ) Wiggle( "wa", 1 ) CI( 1 ) Wiggle( "wa", 1 ) CI( ci2 ) Wiggle( "wa", 1 ) end function srb( ) recentbest.Restore( ) SaveBest( ) end function Fuze( )--is Fuze supposed to be this big ??its like 16 shake,wiggle cycles print( "Fuzing..." ) selection.SelectAll( ) recentbest.Save( ) Fuze1( 0.3, 0.6 ) FuzeEnd( ) Fuze2( 0.3, 1 ) srb( ) Fuze1( 0.05, 1 ) srb( ) Fuze2( 0.7, 0.5 ) FuzeEnd( ) Fuze1( 0.07, 1 ) srb( ) end function FuzeCuts(ci1) local seg = math.random( structure.GetCount() ) -- check for locked frozen ?? Cut( seg ) CI( 1 ) Wiggle( "wa", 15 ) CI( ci1 ) Wiggle( "wa",1 ) CI( 1 ) Wiggle( "wa", 25 ) uncut( seg ) --DeleteCut recentbest.Save( ) --to avoid cuts in recentbest pose Wiggle( "wa", 25 ) CI( ci1 ) Wiggle( "wa", 2 ) CI( 1 ) Wiggle( "wa", 25 ) -- good grief thats a lot of wiggling end-- pauldunn function FuzeWithCuts() print("Fuzing with cuts...") selection.SelectAll() recentbest.Save() Fuze1(0.3,0.6) FuzeEnd() FuzeCuts(0.01) srb() Fuze2(0.3,1) srb() Fuze1(0.05,1) srb() Fuze2(0.7,0.5) FuzeEnd() FuzeCuts(0.1) srb() Fuze1(0.07,1) srb() end -- ------------ END FUZES ------------------ -- ------------------------------------------- -- ------------------------------------------- -- ------------ GENETIC ALGORITHM ------------ -- ------------------------------------------- function CanBeUsed( sg1, sg2 ) --checking end of bands local function AreGood( s1, s2 ) --check that s1 and s2 can be used --cant we just return false instead of setting ok to false ?? local ok = true if s1 == s2 then ok = false end -- no band between same segments if s1 > segCnt or s2 > segCnt then ok = false end --sanity check out of bounds seg if s1 <= 0 or s2 <= 0 then ok = false end --sanity check out of bounds seg if s2 - s1 < bands.minSkip then ok = false end if ok == true and structure.GetDistance( s1, s2 ) < bands.minDist then ok = false end -- 1st condition ??? local lok1 = structure.IsLocked( s1 ) -- true if locked local lok2 = structure.IsLocked( s2 ) -- double lock check local bothlocked = lok1 and lok2 if bothlocked == true then ok = false end --bothlocked = true if both are locked return ok end local ok = AreGood( sg1, sg2 ) -- -------------------------------------------------------------------------------------- -- this needs to be in dialog plus the range code to go with it if ok == true and #DoNotUse > 0 then --none of 2 can be in that area for i = 1, #DoNotUse do local r = DoNotUse[i] for x = r[1], r[2] do if x == sg1 or x == sg2 then ok = false break end end if ok == false then break end end end -- -------------------------------------------------------------------------------------- -- if theres a Ligand 'M' no idea what will happen local function ssCheck( ss ) local good = false if use.Sheet and ss == "E" then good = true end if use.Helix and ss == "H" then good = true end if use.Loop and ss == "L" then good = true end return good end if ok == true then --check structure local check_struct = use.Sheet and use.Helix and use.Loop if check_struct == false then --has check_structure been enabled ok = false local ss1 = structure.GetSecondaryStructure( sg1 ) local ss2 = structure.GetSecondaryStructure( sg2 ) if checkBoth then if ssCheck( ss1 ) and ssCheck( ss2 ) then ok = true end else if ssCheck( ss1 ) or ssCheck( ss2 ) then ok = true end end end end return ok end -- -------------------------------------------------------------------------------------- function SortCritters( ) --bubble sort for i = 1, #critters do for j = i + 1, #critters do if critters[i].score < critters[j].score then critters[i], critters[j] = critters[j], critters[i] --love lua : ) end end end end function ShuffleHerd( ) if herd.shuffle == true then for i = 1, #critters do local r = Randomz( #critters ) if r ~= i then critters[i], critters[r] = critters[r], critters[i] end end end end function FillHerd( ) local n = #critters if n > 0 then --fill up herd n = herd.newRandom else --fresh herd n = herd.breedBest + herd.keepBest + herd.breedBastards end print( "Randomizing "..n.." new critters..." ) for i = 1, n do AddCritter( i, n ) end end function KeepGood( ) --copy best scoring critters form last gen if score above local newHerd = {} for i = 1, herd.keepBest do if critters[i].score > critter.keepScore and ( math.abs( critters[i].score ) > 0.1 or critters[i].score > 0 ) then newHerd[#newHerd + 1] = critters[i] end end return newHerd end function AddCritter( cnum, n ) --create new random critter local c = {} critterID = critterID + 1 c.no = critterID c.name = c.no..'-rnd' c.bands = {} local r = Randomz( critter.minBands, critter.maxBands ) for i = 1, r do c.bands[#c.bands + 1] = AddBand( ) end critters[#critters + 1] = c --print( '( '..cnum..'/'..n..' ) '..c.name.." bands: "..#c.bands ) end -- ==================================================================================================================================== -- here 1 end of band is taken from random or onlyMutable or UseSegments -- then the other end is taken from UseSegments or random then checked with CanBeUsed --sym banding : lengths??, i thnk this could use more work function AddBand( ) --create one random band local cnt = 0 local b = {} while true do --try till die cnt = cnt + 1 local branch = Randomz(structure.GetSymCount() +1)-1 -- 0 if monomer, equal probability for each branch 2020 bk -- ---------------------------------- local s1 = Randomz( segCnt ) -- assign random segment to s1 if onlyMutable == true or #UseSegments > 0 then -- overwrite s1 with new value if either conditions is true s1 = UseSegments[Randomz( #UseSegments )] -- select seg from UseSegments end --hold on if onlyMutable is true tehn usesegments will always be >0 because then it loads UseSEGMNETS with onlymutable segs if alwaysLigand then s1 = LIGAND end -- -------------------------------------------------------------------------------------------------------------------------- local s2 = Randomz( segCnt ) -- assign random segment to s2 if onlyMutable == true then -- overwrite s1 with new value if onlymutable is true s2 = UseSegments[Randomz( #UseSegments )] -- select seg from UseSegments end if s1 > s2 then s1, s2 = s2, s1 end -- ensure s1 is lower than s2 if CanBeUsed( s1, s2 ) then -- check segments are valid local str = Randomz( bands.minStr, bands.maxStr ) -- set band strength local len = 0 while true do --randomize correct distance len = Randomz( -bands.maxDn, bands.maxUp ) if len < -bands.minChng or len > bands.minChng then break end --dont understand this end if band_Oligomer then b = { s1, s2, str, len, branch} --2020 symmetry bands bk else b = { s1, s2, str, len} end break -- break while loop when good band created end if cnt > 750 then print( "Sorry! Cant create band! Breaking script!" ) BreakScript( ) --deliberately no such function, so it terminates recipe. end end return b end -- ------------------------------------------------------------------------------------------ function ScoreHerd( ) --score all critters from herd local selectedsegs = {} save.Quickload( 2 ) -- best pose print( "Scoring "..#critters.." critters..." ) save.Quicksave( 5 ) --Aah SAVE into quicksave 5..Wait..no..that still makes no sense local herdScore = Score( ) for i = 1, #critters do DeleteBands( ) local crt = critters[i] --critter local CritterBaseScore = Score( ) --start score local bnds = crt.bands -- b={s1,s2,str,len, // branch} (len is the random push or pull difference of length) for b = 1, #bnds do local bnd = bnds[b] if bnd[1] ~= bnd[2] then -- no band to itself -redundant now cos of check segs local a1 = 5 -- atom1 central carbon atom local a2 = 5 -- atom2 central carbon atom if bnd[1] == structure.GetCount( ) then a1 = 6 end -- final carbon atom is + 1 if bnd[2] == structure.GetCount( ) then a2 = 6 end if structure.GetAminoAcid( bnd[1] ) == 'g' then a1 = 0 end -- glycine has no beta-carbon .alpha carbon for g is atom 2 ?? if structure.GetAminoAcid( bnd[2] ) == 'g' then a2 = 0 end if not structure.IsHydrophobic( bnd[1] ) and bnd[4]<0 then a1 = 0 end -- only hiding hydrophobics --hows this work?? if not structure.IsHydrophobic( bnd[2] ) and bnd[4]<0 then a2 = 0 end if structure.IsHydrophobic( bnd[1] ) and bnd[4]>0 then a1 = 0 end -- don't push hydropobics to water--?? if structure.IsHydrophobic( bnd[2] ) and bnd[4]>0 then a2 = 0 end -- if atom is 0 what does that do--think it bands to alpha carbon so it dont rotate as freely if structure.GetSecondaryStructure( bnd[1] ) == 'M' then a1 = structure.GetAtomCount(bnd[1]) end--rg ligand hack if structure.GetSecondaryStructure( bnd[2] ) == 'M' then a2 = structure.GetAtomCount(bnd[2]) end--rg ligand hack --this will crash foldit if atom count is wrong which is unlikely but... -- should really wrap this in safe pcall function if band_Oligomer then band.AddBetweenSegments( bnd[1], bnd[2], a1, a2, bnd[5] ) -- 5 is the branch for symmetrics 2020 bk else band.AddBetweenSegments( bnd[1], bnd[2], a1, a2 ) -- this has return value thats sort of checked by 'bc' end local bc = band.GetCount( ) if bc > 0 then selectedsegs[#selectedsegs+1] = bnd[1] -- store banded segs selectedsegs[#selectedsegs+1] = bnd[2] -- store banded segs band.SetStrength( bc, bnd[3] ) local len = structure.GetDistance( bnd[1], bnd[2] ) + bnd[4]-- distance between segments + band length change ( + or - ) if len < bands.minLen then len = bands.minLen end band.SetGoalLength( bc, len ) --print( "Band: "..bnd[1].."-"..bnd[2].." a1: "..a1.." a2: "..a2.." str: "..round( bnd[3] ).." length = "..round( length ) ) end end -- if bnd[1] end -- for b -- ----------------------------------------------------- CI( pullCI ) recentbest.Save( ) local seg = math.random( structure.GetCount( ) ) -- hmm no cuts in locked or frozen Cut( seg ) Wiggle( "wb", 1 ) --this now does 2 iters 'cos of way wiggle() works uncut( seg ) recentbest.Save() -- to avoid recent best in cuts --why here wont recent best now have bands in ??? --great all this kerfuffle for basically these few ilnes DeleteBands( ) -- ------------------------------------------------------ -- select a sphere of segs from band origin point if SmallMutate then --print('Len of selected segs',#selectedsegs) for k, v in ipairs( selectedsegs ) do SelectSphere(v, ShakMutRadius ) end else selection.SelectAll( ) end -- ------------------------------------------------------ if mutateOnce == true then CI( mutateCI ) structure.MutateSidechainsSelected( 1 ) end --Fast Qstab CI( shakeCI ) --was 0.1 Wiggle( "s", 1, nil, true ) --Now always shake selected, if mutatealways then mutate -- plus a qstab threshold ?? threshold should be a percentage if noQstab == false then dbgprint('doing Qstab') CI( 0.4 ) Wiggle( "wa", 1 ) CI( 1 ) Wiggle( "s", 1 )--mutateAlways end CI( 1 ) undo.SetUndo( true ) -- UNDO - So undo graph has at least seomthing in it Wiggle( ) undo.SetUndo( false ) -- UNDO -- --------------------------------------------------------------------------- --use filters for fuze check and fuze if required --fuze selects all --2 shakes at least so 2 calls to mutatealways with all selected DoFuze() SaveRB( ) -- --------------------------------------------------------------------------- selection.DeselectAll( )--rg crt.score = Score( ) - CritterBaseScore print( "( "..i.."/"..( #critters ).." ) Critter "..crt.name.." : "..round( crt.score ),round( Score() ) ) -- --------------------------------------------------------------------------- --Not checked but --this needs sorting out filters trash Score() --how does this work anyway ??? --quicksave 5 is never integrated into quicksave 2 --What is this supposed to do ?? if critter.maxLoss > 0 then --print('maxloss', Score(), herdScore) if Score( ) > herdScore - critter.maxLoss then save.Quicksave( 5 ) herdScore = Score( ) else save.Quickload( 5 ) end else save.Quickload( 2 ) end --dbgprint('#selectedsegs'..#selectedsegs) for key in pairs ( selectedsegs ) do --empty selectedsegs table but preserve reference selectedsegs[key] = nil end -- --------------------------------------------------------------------------- end -- for i save.Quickload( 2 ) if band.GetCount( ) > 0 then --clean bands from best solution ( if any ) DeleteBands( ) save.Quicksave( 2 ) end end function BreedCritters( mom, dad, t ) --breed 2 critters. bands are taken randomly from parents local kid = {} critterID = critterID + 1 kid.no = critterID kid.name = kid.no.."-"..t..mom.no..'/'..dad.no kid.bands = {} local mb = #mom.bands local db = #dad.bands if mb > db then mb, db = db, mb end -- kids have band count between mom and dad band count local bn = Randomz( mb, db ) -- random num bands, min=mom , max= dad for i = 1, bn, 2 do -- every other kid.bands[#kid.bands + 1] = mom.bands[Randomz( #mom.bands )] -- random chromosome selection kid.bands[#kid.bands + 1] = dad.bands[Randomz( #dad.bands )] end --print( kid.name.." bands: "..#kid.bands ) return kid end function BreedHerd( ) print( "Breeding..." ) SortCritters( ) newHerd = KeepGood( ) for i = 1, herd.breedBest do local mom = critters[i] if mom.score > critter.breedScore or i < 2 then --breed only good ones, 1st is always breed anyway for j = i + 1, herd.breedBest do local dad = critters[j] newHerd[#newHerd + 1] = BreedCritters( mom, dad, "kid-" ) newHerd[#newHerd + 1] = BreedCritters( dad, mom, "kid-" ) end end end for i = 1, herd.breedBastards do --they will always appear ;] local mom = critters[i] local j = Randomz( herd.breedBastards + 1, #critters ) local dad = critters[j] newHerd[#newHerd + 1] = BreedCritters( mom, dad, "bas-" ) newHerd[#newHerd + 1] = BreedCritters( dad, mom, "bas-" ) end critters = newHerd FillHerd( ) end --==================================================================== function LoadUseSegmentsList() --How to combine the logic of DoNotUse, AlwaysUse, UseSegments and OnlyMutable ??? if onlyMutable == true then for i = 1, segCnt do if structure.IsMutable( i ) then UseSegments[#UseSegments+1] = i end end end if #AlwaysUse > 0 then --this WILL add dupes to UseSegments, slack but not really a problem for i = 1, #AlwaysUse do local ss = AlwaysUse[i][1] local se = AlwaysUse[i][2] if ss > se then ss, se = se, ss end for j = ss, se do UseSegments[#UseSegments+1] = j end end AlwaysUse={} --added to list, canbeused check for this is now redundant --now these segs are in canbeused then they MIGHT be used in a critter --rather than they should ALWAYS be 1 from this list per critter --Is this implemented wrongly ?? Its not like this in GABBiS end end -- ----------------------------------------------------- function GAB( ) LoadUseSegmentsList() CleanUseSegments( ) -- bounds check on seg nums critterID = 0 gen = 0 ss = Score( ) ssstr = ( round( ss ) ) save.Quicksave( 2 ) recentbest.Save( ) print( "Start score: "..round( ss ) ) critters = {} FillHerd( ) badGen = 0 while true do --this is ( almost ) endless script ;] genScore = Score( ) gen = gen + 1 print( ) print( "Generation: "..gen.." ( "..( os.date( ) ).." )") print("Score: "..round( Score( ) )..", gain: "..round( Score() -ss ) ) ShuffleHerd( ) ScoreHerd( ) save.Quickload( 2 ) if gen == herd.maxGen then break end --end of script if genScore >= Score( ) then badGen = badGen + 1 else badGen = 0 end --fixed if badGen >= herd.renew then print( " ** Creating fresh random herd **" ) critters = {} FillHerd( ) badGen = 0 else BreedHerd( ) end genEndScore = Score( ) genGain = genEndScore - genScore if gen > 1 and ( gen-1 ) == 5 * down( ( gen-1 )/5 ) then ssstr = ( ssstr..'\n ' ) -- start new line every 5 generations end if genGain >= 0 then ssstr = ( ssstr..' + '..round( genGain ) ) else ssstr = ( ssstr..' - '..( -round( genGain ) ) ) end print( ssstr..' = '..round( genEndScore ) ) end -- while true save.Quickload( 2 ) -- best pose DeleteBands( ) selection.DeselectAll() if TvdLFilteractive then FilterOn( ) end print( "Final score: "..round( Score( ) ).." Total gain: "..round( Score( ) - ss ) ) end -- GAB( ) -- -- - -- -- ------------------------------------------- -- ----------------- DIALOGS ----------------- -- ------------------------------------------- function MoreDialogOptions( ) local opt2 = dialog.CreateDialog( ReVersion ) opt2.spacer_0 = dialog.AddLabel( "More Options." ) opt2.fuzeth = dialog.AddTextbox( "Fuze threshold: ", fuzeThresh ) opt2.spacer_1 = dialog.AddLabel( " " ) opt2. mutsmall = dialog.AddCheckbox("Use fewer segs :: affects Shake and Mutate", SmallMutate ) opt2.spacer_2 = dialog.AddLabel( "Sphere size for use fewer segs " ) opt2. shakmutrad = dialog.AddSlider( "Sphere", ShakMutRadius, 1,16,0 ) opt2.mutci = dialog.AddSlider( "Mutate CI", mutateCI , 0.1, 1, 2 ) -- mutate on what clashing importance opt2.minimumgain = dialog.AddSlider( "Min Gain", MINGAIN, 0, 75, 0 ) opt2.spacer_3 = dialog.AddLabel( " " ) opt2.run = dialog.AddButton( "Back", 1 ) dialog.Show( opt2 ) fuzeThresh = tonumber( opt2.fuzeth.value ) MINGAIN = opt2.minimumgain.value SmallMutate = opt2.mutsmall.value ShakMutRadius = opt2.shakmutrad.value mutateCI= opt2.mutci.value end -- -- - -- function GADialogOptions( ) local opt1 = dialog.CreateDialog( "Genetic Algorithm Options" ) opt1.lbl1 = dialog.AddLabel( "Herd:" ) opt1.brbest = dialog.AddSlider( "Breed best", herd.breedBest, 1, 20, 0 ) opt1.kbest = dialog.AddSlider( "Keep best", herd.keepBest, 1, 20, 0 ) opt1.bas = dialog.AddSlider( "Breed bastards", herd.breedBastards, 1, 20, 0 ) opt1.rnd = dialog.AddSlider( "New random", herd.newRandom, 1, 30, 0 ) opt1.renew = dialog.AddSlider( "Renew herd", herd.renew, 1, 10, 0 ) opt1.shuff = dialog.AddCheckbox( "Shuffle critters", herd.shuffle ) opt1.lbl2 = dialog.AddLabel( "Critter:" ) opt1.minb = dialog.AddSlider( "Minimum bands:", critter.minBands, 1, 4, 0 ) opt1.maxb = dialog.AddSlider( "Maximum bands:", critter.maxBands, 4, 50, 0 ) opt1.keeps = dialog.AddSlider( "Keep score:", critter.keepScore, -10, 10, 0 ) opt1.breeds = dialog.AddSlider( "Breed score:", critter.breedScore, -40, 10, 0 ) opt1.maxloss = dialog.AddSlider( "Max loss:", critter.maxLoss, 0, 50, 0 ) opt1.lbl4 = dialog.AddLabel( "( 0 to disable max loss )" ) opt1.lbl3 = dialog.AddLabel( "Bands:" ) opt1.minst = dialog.AddSlider( "Min str", bands.minStr, 0.1, 2, 1 ) opt1.maxst = dialog.AddSlider( "Max str", bands.maxStr, 0.2, 2, 1 ) opt1.maxup1 = dialog.AddSlider( "Max length", bands.maxUp, 1, 20, 0 ) opt1.minlen = dialog.AddSlider( "Min length", bands.minUp, 0, 6, 0 ) opt1.run = dialog.AddButton( "Back", 1 ) dialog.Show( opt1 ) herd.breedBest = opt1.brbest.value herd.keepBest = opt1.kbest.value herd.breedBastards = opt1.bas.value herd.newRandom = opt1.rnd.value herd.shuffle = opt1.shuff.value herd.renew = opt1.renew.value critter.minBands = tonumber( opt1.minb.value ) critter.maxBands = tonumber( opt1.maxb.value ) critter.keepScore = tonumber( opt1.keeps.value ) critter.breedScore = tonumber( opt1.breeds.value ) critter.maxLoss = tonumber( opt1.maxloss.value ) minStr = opt1.minst.value --minimum band str maxStr = opt1.maxst.value --maximum band str maxUp = opt1.maxup1.value --maximum change up ( push ) :: maximum band len minLen = opt1.minlen.value --minimum length of created band end -- -- - -- function DialogOptions( ) local dialogresult local opt = dialog.CreateDialog( ReVersion ) repeat opt.lbl1 = dialog.AddLabel( ReVersion.." main options:" ) opt.gen = dialog.AddTextbox( "Generations:", herd.maxGen ) opt.WF = dialog.AddSlider( "WiggleFactor:",WF, 1, 5, 0 ) opt.pull = dialog.AddSlider( "Pulling CI", pullCI, 0.05, 1, 2 )--description, default, min, max, precision opt.shak = dialog.AddSlider( "Shake CI", shakeCI, 0.01, 1, 2 ) opt.capci = dialog.AddCheckbox( "Cap CI, Otherwise Relative CI", CapCI ) opt.usermaxci = dialog.AddSlider( "Maximum CI", userSetMaxCI, 0.05, 1, 2 ) opt.skipqstab = dialog.AddCheckbox( "Skip Qstab", noQstab ) --put in 'More options' ? opt.skipfuze = dialog.AddCheckbox( "Skip Fuze", noFuze ) --put in 'More options' ? opt.spacer1 = dialog.AddLabel( " " ) if HASMUTABLE then opt.mutonly = dialog.AddCheckbox( "Only mutable", onlyMutable ) opt.mutonce = dialog.AddCheckbox( "Mutate once", mutateOnce ) opt.mutalways = dialog.AddCheckbox( "Mutate always", mutateAlways ) opt.spacer3 = dialog.AddLabel( " " ) end if HASLIGAND then opt.hasligand = dialog.AddCheckbox("Always use LIGAND ", alwaysLigand ) end if SYMMETRICBANDS then opt.AllowSymmetrybands = dialog.AddCheckbox("Allow symmetry bands: ", band_Oligomer ) opt.spacer4 = dialog.AddLabel( " " ) end if USERBANDS > 0 then opt.label2 = dialog.AddLabel( " !! User bands found !!" ) opt.keepbands = dialog.AddCheckbox( "Keep user bands", keep_bands ) opt.spacer2 = dialog.AddLabel( " " ) end opt.run = dialog.AddButton( "Start", 1 ) opt.more = dialog.AddButton( "More", 2 ) -- threshold and such opt.morega = dialog.AddButton( "GA", 3 ) -- want most GA and/or numeric params in here opt.cancel = dialog.AddButton( "Cancel", 0 ) dialogresult = dialog.Show( opt ) if dialogresult > 0 then herd.maxGen = tonumber( opt.gen.value ) WF = opt.WF.value pullCI = opt.pull.value shakeCI = opt.shak.value CapCI = opt.capci.value userSetMaxCI = opt.usermaxci.value noQstab = opt.skipqstab.value -- negative logic..makes Robert Martin cry :'-( noFuze = opt.skipfuze.value -- negative logic if USERBANDS > 0 then keep_bands = opt.keepbands.value end if HASMUTABLE then onlyMutable = opt.mutonly.value mutateOnce = opt.mutonce.value mutateAlways = opt.mutalways.value end if HASLIGAND then alwaysLigand = opt.hasligand.value end if SYMMETRICBANDS then band_Oligomer = opt.AllowSymmetrybands.value end if dialogresult == 2 then MoreDialogOptions( ) end if dialogresult == 3 then GADialogOptions( ) end end until dialogresult < 2 return dialogresult end -- ------------------------------------------- -- -------------- END DIALOG ----------------- -- ------------------------------------------- function Prelim( ) --wonder if lesser values are changed from default they can be flagged and printed print( ReVersion ) print( 'puzzle '..( puzzle.GetName( ) ) ) save.Quicksave( 1 ) --OG backup- after dialog so if cancelled in dialog these positions are still intact save.Quicksave( 2 ) --best pose print('Start pose in Quicksave 1') print('Best pose in Quicksave 2') -- changed to slot 2 print('Generations to run:', herd.maxGen) if MINGAIN > 1 then print ("Minimum Gain is set to:", MINGAIN) end if USERBANDS > 0 then if keep_bands then print( '= Using '..USERBANDS..' user-supplied bands.' ) else print( '= REMOVING '..USERBANDS..' user-supplied bands.') USERBANDS = 0 band.DeleteAll() end end if CapCI then print('= CI is capped at:', userSetMaxCI) else print('= CI is relativised from:', userSetMaxCI) end local wigglepowuh = WigglePowerShowSettting( ) print("= Wiggle power :", wigglepowuh ) print('= Wiggle factor:', WF) if noFuze == true then print("= Fuze is: OFF") else print("= Fuze is: ON :: threshold is:", fuzeThresh) end if noQstab == true then print("= Qstab is: OFF") else print("= Qstab is: ON") end if HASMUTABLE then print('= MUTABLE puzzle') if mutateOnce or mutateAlways then print('= Mutate is: ON') else print('= Mutate is: OFF') end end if HASLIGAND then print('= LIGAND puzzle') print('= LIGAND is :',LIGAND) if alwaysLigand then print('= Always use LIGAND is: ON' ) else print('= Always use LIGAND is: OFF') end end if SYMMETRICBANDS then local is_sym = SymCheck() is_sym = is_sym +1 print('= SYMMETRIC puzzle with C'..is_sym..' symmetry') if band_Oligomer then print('= Symmetry banding is: ON') else print('= Symmetry banding is: OFF') end end end -- ------------------------------------------------------- -- main call function Main( ) HasMutableCheck( ) -- toggles global HASMUTABLE SymCheck( ) -- toggles global SYMMETRICBANDS HasLigandCheck( ) SeedRandom( ) local go = DialogOptions( ) if go == 1 then Prelim( ) --print the settings GAB( ) else print( 'Cancelled' ) return end undo.SetUndo( true ) behavior.SetClashImportance( userSetMaxCI )-- return to user setting end -- ------------------------- xpcall( Main, Cleanup ) --GAB_proj_beta_v1.3.2 -- ---------- END RECIPE -------------------- -- ------------------------------------------ -- ------------------------------------------

Comments


robgee Lv 1

– CodeBase: Rav3n_pl GAB 2.0.6

Added:
Timo_vdL. Filters, Dialogs, some Bruno_K. GAB mods,
CI-slider, select-sphere for mutate/shake, other stuff.

Basically: Rav3n_pl GAB with Dialogs and a few bells and whistles.