Icon representing a recipe

Recipe: LigandDockerFast1000

created by rosie4loop

Profile


Name
LigandDockerFast1000
ID
108288
Shared with
Public
Parent
Ligand docker v2.3
Children
Created on
May 20, 2023 at 09:21 AM UTC
Updated on
October 18, 2023 at 03:57 AM UTC
Description

Basically same as the parent. Just changing the default
values and commented away the dialog for an
automatic quick run. Not removing the dialog codes in
case I want them back later.

Setting the following values in GUI of Ligand Docker v2.3
is equivalent to this version:

1000 1 0 1 25 5 5 6299 1.5 1 0

I use these values for a quick run of pose refinement
with minimal alteration to the torsions.

Best for


Code


-- Ligand docker fast auto 1000 cycles, minor modification from parent -- Ligand docker v2.3 -- Credits: Raven_pl,Susume,LociOiling,lynnai, -- robgee,jeff101 -- dev version : Ligand docker BiS RW v1.5 -- It makes BiS bands to move the Ligand thru space, -- hopefully finding a better position, -- every so often it moves the Ligand extra far -- to try and optimize its search strategy for finding a better position. -- This type of search is based on a Levy flight (e should be accented on Levy), -- Sharks and Albatrosses use it. -- It is not a proper random walk/Levy flight because -- frankly i dont know how to do that with spacebands. -- To Do: -- Band X,Y atoms ???? -- toggle for wiggle(backbone),wiggle(all) -- ------------------------------------ -- 7/01/2020 for v2.1b, jeff101 changed input upper limits -- for Wiggles to 500 and for minDist & maxDist to 50000. -- Setting minDist to 3000 & maxDist to 25000 -- lets the actual band lengths used range from 3-25 Angstroms. -- This recipe seems to assume the protein's final segment -- is the one and only ligand. -- 7/16/2020 for v2.2, jeff101 allowed more than 2 bands -- to the ligand. Unclear if Levy random walk will still work -- as intended, even using just 2 bands. -- 8/07/2020 for v2.3, jeff101 let # cycles between reverts -- and Levy use vary. Changed minDist & maxDist input upper -- limits to 150000. Changed many default values. -- 8/09/2020 for v2.3, jeff101 changed goal length for bands -- from 3.5 (the default value) to 0. -- Ideas for later: -- Use textboxes not sliders to input minDist and maxDist. -- Let user pick default random seed or input his own value. -- Break up wiggling without bands into shorter intervals. -- If gain doesn't pass a threshold, quit wiggling. -- If gain passes a threshold, continue wiggling. -- last updated 8/10/2020 657am -- ------------------------------------ -- ---------- GLOBAL VARS ------------- -- ------------------------------------ Recipe = "Ligand Docker v2.3" Version = "fast-autorun" ReVersion = Recipe .. " " .. Version OrigBands = band.GetCount() -- # of user-supplied bands at start -- - -- ------------- OPTIONS -------------- -- - Cycles = 1000 --was 30 before 8/7/2020. RevertCycles = 1 --# of cycles between revert to best score. --0 means never revert to best score. --was 5 before 8/9/2020. LevyCycles = 0 --# of cycles between uses of Levy. --0 means never use Levy. --was 8 before 8/9/2020. WigWithBands = 1 --how much to wiggle with bands. was 1 before 8/7/2020. Wiggles = 25 --how much to wiggle with no bands. was 3 before 8/7/2020. AtomsInLigand = 0 --# of atoms in the ligand. BandsToLigand = 5 --# of bands from ligand to space. was 2 before 8/7/2020. minDist = 5 --was 10 before 8/7/2020. maxDist = 6299 Levy = 0 BandStrength = 1.5 CapCI = false userSetMaxCI = behavior.GetClashImportance() Verbosity = 0 -- 0 = the least output messages, 2 = the most output messages -- END OPTIONS segCnt = structure.GetCount() numSegs =structure.GetCount() highscore = 0 BASESCORE = current.GetEnergyScore() -- ------------------------------------------- -- List all the recipe's functions below: -- ------------------------------------------- function HasLigandCheck( ) alwaysLigand = false segCnt2 = segCnt while structure.GetSecondaryStructure(segCnt2)=="M" do segCnt2 = segCnt2-1 end -- while -- line below looks odd to jeff101 8/7/2020 HASLIGAND = segCnt2 < segCnt -- is line above the same as the line below? -- HASLIGAND = (segCnt2 < segCnt) if HASLIGAND then LIGAND = segCnt AtomsInLigand = structure.GetAtomCount(LIGAND) alwaysLigand = true end -- if HASLIGAND end -- HasLigandCheck() function round ( x )--to 3 places return x - x % 0.001 end -- round() -- ----------------------------------------------------- function CI( RecipeCI ) -- Cap CI else relative CI 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 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 Cleanup(err) -- cancel recipe function if CLEANUPENTRY ~= nil then return end CLEANUPENTRY = true --LO print( '========================' ) print( ReVersion..': Cleaning Up.' ) save.Quickload( 2 ) selection.DeselectAll() delete_temp_bands() behavior.SetClashImportance( userSetMaxCI ) print( "Final score: "..round( highscore ) ) print( "Total gain: " ..round( highscore - BASESCORE ) ) print( "Error "..err) -- ..err prints no space before err -- print( "Error",err) -- ,err prints tab before err end -- Cleanup() -- ----------------------------------------- function delete_temp_bands() local TempBands=band.GetCount() for bnum=TempBands, OrigBands+1, -1 do band.Delete(bnum) end -- for bnum end -- delete_temp_bands() -- ----------------------------------------- function random_bands() local hscore = current.GetScore() print("Cycle start score: "..round( hscore ) ) local OG = LIGAND if BandStrength >10.0 then BandStrength = 9.99 end minDist = minDist + Levy maxDist = maxDist + Levy -- minDist, maxDist, Levy are all in 0.001 Angstroms above local HasBand={} -- an array of 0's or 1's with length BandsToLigand local origval=0 local ngot=0 local ntoget=BandsToLigand if 2*BandsToLigand>AtomsInLigand then origval=1 ntoget=AtomsInLigand-BandsToLigand end for anum=1, AtomsInLigand do HasBand[anum]=origval end -- for anum if Verbosity>1 then if origval==0 then print('Banding the '..ntoget..' ligand atoms below:') else print('Banding all but the '..ntoget..' ligand atoms below:') end end -- if Verbosity while ngot<ntoget do anum=math.random(1,AtomsInLigand) if HasBand[anum]==origval then ngot=ngot+1 HasBand[anum]=1-origval if Verbosity>1 then print(string.format('(%3d) %3d',ngot,anum)) end -- if Verbosity end -- if HasBand end -- while ngot -- ngot should equal ntoget here -- make all BandsToLigand bands below if Verbosity>=0 then print('Levy,minDist,maxDist='..Levy..','..minDist..','..maxDist..' in 0.001 Angstroms') end -- if Verbosity ngot=0 for anum=1, AtomsInLigand do if HasBand[anum]==1 then ngot=ngot+1 local dst = math.random( minDist, maxDist ) local RHO=(dst / 1000) --RHO is a distance in Angstroms -- while Levy, dst, minDist, maxDist are distances in 0.001 Angstroms --print('Distance '..RHO) local theta = math.acos(math.random( ) ) local phi = 2 * math.pi * math.random( ) repeat Xaxis=math.random( 1, numSegs-1 ) Yaxis=math.random( 1, numSegs-1 ) until OG ~= Xaxis and Yaxis ~= Xaxis and OG ~= Yaxis --print(OG,Xaxis,Yaxis) all 3 must be different segment #'s -- {segmentOrigin, segmentXAxis, segmentYAxis, rho, theta, phi, Oatom, Xatom, Yatom} -- Xatom & Yatom below are for alpha-carbons on segments Xaxis & Yaxis local Xatom = 0 local Yatom = 0 local OriginAtom = anum local qed = band.Add(OG, Xaxis, Yaxis, RHO, theta, phi, OriginAtom, Xatom, Yatom ) -- above gives 3.5 as the default goal length for band qed -- above gives 1.0 as the default strength for band qed -- RHO is the initial actual length for band qed if qed >= 1 then band.SetGoalLength(qed,0) -- set band qed's goal length to 0 band.SetStrength(qed,BandStrength) if Verbosity>0 then print(string.format('(%3d) Band ligand atom %3d with %7.3f Angstroms.', ngot,anum,RHO)) end -- if Verbosity end -- if qed end -- if HasBand end -- for anum -- ngot should equal BandsToLigands here -- make all BandsToLigand bands above selection.DeselectAll () selection.Select ( OG ) -- selects the ligand CI(0.88) local witers = WigWithBands --structure.ShakeSidechainsSelected(witers) --structure.WiggleSelected(witers, true, true) -- moves ligand through space and bends it. --structure.WiggleSelected(witers, true, false) -- moves ligand through space but does not bend it. structure.WiggleSelected(witers, true, true) -- moves ligand through space and bends it. -- ----------------------------------------------------------------------------------------------------- delete_temp_bands() if Verbosity>=0 then print('After banded wiggle: '..round(current.GetEnergyScore())) end CI(1.0) --structure.ShakeSidechainsSelected( 2 ) structure.WiggleAll( Wiggles , true, true ) -- above moves ligand thru space and lets it bend. -- above also moves protein backbone and sidechains. newscore = current.GetEnergyScore() print('After unbanded wiggle: '..round(newscore)) if newscore > highscore then save.Quicksave( 2 ) recentbest.Save( ) local gain = newscore - highscore print('gain: '..round(gain)) highscore = newscore print("++ High score = "..round(highscore)) end selection.DeselectAll() print('') end -- random_bands() function LigandDock() highscore = current.GetScore( ) local revertscore = current.GetScore( ) for i = 1, Cycles do Levy = 0 revertscore = current.GetScore( ) -- RevertCycles == 0 should skip the following every cycle i if RevertCycles ~= 0 then if i % RevertCycles == 0 and revertscore <= highscore then print(' -- reverting to best position --') save.Quickload( 2 ) end end -- LevyCycles == 0 should skip the following every cycle i if LevyCycles ~= 0 then if i % LevyCycles == 0 and revertscore <= highscore then print(' -- Implementing Levy flight --') Levy = math.random( 500, 800 ) -- Levy should be an integer from 500 to 800 now end end print('Cycle '..i..' of '..Cycles..' at '..os.date()..':') random_bands() end -- for i end -- LigandDock() -- --- ---------------------------------------------------------- -- function Prelim() print( ReVersion ) save.Quicksave( 1 ) --OG pose for backup save.Quicksave( 2 ) --for high score print('Start pose in Quicksave 1') print('Best pose in Quicksave 2') print("Levy flight version, with random distance") print("Protein length: "..structure.GetCount() ) print('# of Ligand Atoms: '..AtomsInLigand) print('# of User-Supplied Bands: '..OrigBands) print('') print('Total # of Cycles to do: '..Cycles) print('# of Cycles per Revert: '..RevertCycles..' (0 means never Revert)') print('# of Cycles per Levy: '..LevyCycles..' (0 means never use Levy)') print('# of Wiggles with Bands per Cycle: '..WigWithBands) print('# of Wiggles without Bands per Cycle: '..Wiggles) print('# of Bands from Space to Ligand: '..BandsToLigand) print('Minimum Band Length: '..minDist..' ('..(minDist/1000)..' Angstroms)') print('Maximum Band Length: '..maxDist..' ('..(maxDist/1000)..' Angstroms)') -- 8/10/2020 jeff101 thinks minDist & maxDist are given in 0.001 Angstroms -- so that math.random(minDist,maxDist) gives an integer from minDist to maxDist print('Band Strength: '..BandStrength ) print('Maximum CI recipe will use: '..userSetMaxCI ) print('Verbosity: '..Verbosity) print("Recipe start score: "..round(current.GetEnergyScore())) print('') end -- Prelim() function DialogOptions() local dlog = dialog.CreateDialog(ReVersion) dlog.iters = dialog.AddSlider("Cycles",Cycles,1,1000,0) dlog.revcyc = dialog.AddSlider("Revert Cycles",RevertCycles,0,10,0) dlog.levycyc = dialog.AddSlider("Levy Cycles",LevyCycles,0,10,0) dlog.wwb = dialog.AddSlider("Banded Wiggles",WigWithBands,1,500,0) dlog.wigls = dialog.AddSlider("Free Wiggles",Wiggles,1,500,0) dlog.spacer1 = dialog.AddLabel('') dlog.bnd2lig = dialog.AddSlider('# Ligand Bands',BandsToLigand,1,AtomsInLigand,0) dlog.minidist = dialog.AddSlider('Min Band Length',minDist, 5,150000,0) dlog.maxidist = dialog.AddSlider('Max Band Length',maxDist,20,150000,0) dlog.bandstren = dialog.AddSlider('Band Strength',BandStrength,0.1,5,1) dlog.usermaxci = dialog.AddSlider("Maximum CI",userSetMaxCI,0.00,1,2) dlog.spacer3 = dialog.AddLabel('') dlog.vrb = dialog.AddSlider('Verbosity',Verbosity,0,2,0) dlog.ok = dialog.AddButton("OK",1) dlog.cancel = dialog.AddButton("Cancel",0) dialogresult = dialog.Show(dlog) if dialogresult > 0 then Cycles = dlog.iters.value RevertCycles = dlog.revcyc.value LevyCycles = dlog.levycyc.value WigWithBands = dlog.wwb.value Wiggles = dlog.wigls.value BandsToLigand = dlog.bnd2lig.value minDist = dlog.minidist.value maxDist = dlog.maxidist.value BandStrength = dlog.bandstren.value userSetMaxCI = dlog.usermaxci.value Verbosity = dlog.vrb.value end return dialogresult end -- DialogOptions() function Main() SeedRandom() HasLigandCheck( ) if HASLIGAND == false then print('This is NOT a LIGAND puzzle ... exiting') return end local go = 1 --DialogOptions( ) if go == 1 then Prelim( ) --print the settings LigandDock( ) else print( 'Cancelled' ) return end -- restore best score and print it below save.Quickload( 2 ) local tmpscore=current.GetScore() print('Restoring best score: '..round(tmpscore)) undo.SetUndo( true ) behavior.SetClashImportance( userSetMaxCI ) -- return to user setting end -- Main() xpcall( Main, Cleanup ) --Ligand docker v2.3

Comments


rosie4loop Lv 1

The recent reranking puzzles got multiple ligands to be evaluated, players who don't have a lot of time to play may want to refine poses with minimal number of clicks and speed runs.

Hence I'm sharing this version hoping it can be useful. But note that the code is basically the same as Ligand Docker v2.3 shared by jeff101.

Edit: Remarks on usage
Usually I do all the ligand placement, torsion adjustment, conformation sampling, initial shake and wiggle by hand. Once I'm happy with the binding mode, I run this recipe for a quick refinement. Because I don't have a lot of time to play, I usually run it for less than 100 cycles, stop it when it's not scoring for around 10 cycle, then end it with several cycles of AFK3Fast. Then I move on to the next compound from library or ligand queue.