Icon representing a recipe

Recipe: Ligand docker v2.3

created by jeff101

Profile


Name
Ligand docker v2.3
ID
103794
Shared with
Public
Parent
Ligand docker v2.3
Children
Created on
August 10, 2020 at 12:51 PM UTC
Updated on
August 10, 2020 at 12:51 PM UTC
Description

*2.3a3.txt 8/10/2020 657am code

Best for


Code


-- 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" Version = "v2.3" ReVersion = Recipe .. " " .. Version OrigBands = band.GetCount() -- # of user-supplied bands at start -- - -- ------------- OPTIONS -------------- -- - Cycles = 1000 --was 30 before 8/7/2020. RevertCycles = 2 --# of cycles between revert to best score. --0 means never revert to best score. --was 5 before 8/9/2020. LevyCycles = 3 --# of cycles between uses of Levy. --0 means never use Levy. --was 8 before 8/9/2020. WigWithBands = 30 --how much to wiggle with bands. was 1 before 8/7/2020. Wiggles = 200 --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 = 50 Levy = 0 BandStrength = 1.50 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 = 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


jeff101 Lv 1

When I run this recipe, I usually give it the following input values from top to bottom:
1000 1 0 30 200 5 5 6299 1.5 1.00 2. Then I let the recipe run until it has done 100
cycles in a row with no gain. To see when the recipe gained points, I search its output
in the scriptlog.default.xml file for 'gain' or '++' using an editor like Notepad.

If you have found different input values to work better than the ones listed above,
please post about it below. Thanks!

rosie4loop Lv 1

For a quick run of pose refinement with minimal alteration to the torsions I use the following:
1000 1 0 1 25 5 5 6299 1.5 1 0

I found that if the ligand is somehow flexible, any value higher than 1 for banded wiggle likely results an unwanted torsion, which cannot be corrected even after 200 unbanded wiggles. Max length of 6299 is usually good enough for (slightly) displacing it.

But if it's desirable to let the script explore different torsions and to do a more exhaustive search of pocket space, better increase the number of wiggles, e.g. use the default values. I do these manually just to train myself to work on 3D structures.