Profile
- Name
- Bravo Hydro PulleR v3.0
- ID
- 108953
- Shared with
- Public
- Parent
- Rav3n_pl Hydro PulleR v2.1
- Children
- Created on
- December 30, 2024 at 15:11 PM UTC
- Updated on
- July 20, 2025 at 18:10 PM UTC
- Description
Pull all hydrophobic to all other hydrophobics in loop
Best for
Code
--[[
Bravo Random Hydro Puller v3.0 based on Rav3n_pl Hydro PulleR v2.1
Pulling all hydrophobes to all hydrophope segments
v2.1 - Using 1st sidechain atom to pull.
v3.0 - Using tip atom of the sidechain instead of beta carbon to pull.
- Removed Random segment selection and loop count. changed to try every hydrophobic segment instead.
- added repeat main if score improvement was found. no try forever or arbitrary number.
]] --
--- OPTIONS
minBS = 0.3 --starning minimum bands strenght
maxBS = 1.0 --maximum bads str
maxLoss = 10 --minimum percentage loss when pulling. ie 5% of 10000 is 500pts
pullingCI = 0.6 --clash importance while pulling
fastQstab = true -- for 1s1w as stabilize (faster)
doFuze = 100 --run fuze when score after qstabilize is close to best. If negative run fuze only if gain after qstab
energy = false --set true for exploration puzzles if want seek stability
pullDist = 4 --make bands shorter by that many units
minDist = 2 --minimum distance between segments
-- end of options
-- Initialize variables
local starting_score = current.GetScore()
local best_score = starting_score
local segment_count = structure.GetCount()
math.randomseed(recipe.GetRandomSeed())
p = print
CI = behavior.SetClashImportance
segCnt = structure.GetCount()
while structure.GetSecondaryStructure(segCnt) == 'M' do
segCnt = segCnt - 1
end
function Score()
local s
if energy == true then
s = current.GetEnergyScore()
else
s = current.GetScore()
end
return s
end
function round(x) --cut all afer 3-rd place
return x - x % 0.001
end
function abs(x)
if x < 0 then
x = -x
end
return x
end
function Wiggle(how, iters, minppi) --score conditioned recursive wiggle/shake
if how == nil then
how = 'wa'
end
if iters == nil then
iters = 6
end
if minppi == nil then
minppi = 0.1
end
if iters > 0 then
iters = iters - 1
local sp = Score()
if how == 's' then
structure.ShakeSidechainsSelected(1)
elseif how == 'wb' then
structure.WiggleAll(2, true, false)
elseif how == 'ws' then
structure.WiggleAll(2, false, true)
elseif how == 'wa' then
structure.WiggleAll(2)
end
if Score() - sp > minppi then
return Wiggle(how, iters, minppi)
end
end
end
function AllLoop() --turning entire structure to loops
local ok = false
for i = 1, segCnt do
local s = structure.GetSecondaryStructure(i)
if s ~= 'L' then
save.SaveSecondaryStructure()
ok = true
break
end
end
if ok then
selection.SelectAll()
structure.SetSecondaryStructureSelected('L')
end
end
function RandomInt(high)
return math.random(high)
end
function SaveBest()
local s = Score()
local g = s - best_score
if g > 0 then
if g > 0.01 then
p('Gained another ' .. round(g) .. ' pts.')
end
best_score = s
save.Quicksave(1)
end
end
function bandstr(str) --set all band strengt
for i = 1, band.GetCount() do
band.SetStrength(i, str)
end
end
function down(x) --cut all after comma
return x - x % 1
end
function round(x) --cut all afer 3-rd place
return x - x % 0.001
end
function SaveRB()
save.Quicksave(4)
recentbest.Restore()
SaveBest()
save.Quickload(4)
end
function qStab()
selection.SelectAll()
CI(0.1)
Wiggle('s', 1)
if fastQstab == false then
CI(0.4)
Wiggle('wa', 1)
CI(1)
Wiggle('s', 1)
end
CI(1)
Wiggle()
end
function FuzeEnd()
CI(1)
Wiggle('wa', 1)
Wiggle('s', 1)
Wiggle()
srb()
end
function Fuze1(ci1, ci2)
CI(ci1)
Wiggle('s', 1)
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()
p('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 MakeBands(pullSg)
band.DeleteAll()
for i = 1, segCnt do
if structure.IsHydrophobic(i) then
local bn1 = band.GetCount()
local setDist = structure.GetDistance(i, pullSg) - pullDist - minDist
if setDist > 1 then
band.AddBetweenSegments(i, pullSg, atomIndex(i), atomIndex(pullSg)) --pull using tip of sidechain segment
bn1 = band.GetCount() - bn1
if bn1 > 0 then
band.SetGoalLength(band.GetCount(), setDist)
end
end
end
end
end
-- Custom atom indices for each amino acid type with inline comments
-- Indices atom values for the tip of the side chains.
-- There might be a better index to pull to hide the side chain better. play around with these.
-- 20 common amino acids. doesn't handle unkown or ligands
atom_indices = {
a={5}, --a-ALA-Alanine
c={6}, --c-CYS-Cystein
d={6}, --d-ASP-Aspartate
e={7}, --e-GLU-Glutamate
f={11}, --f-PHE-Phenylalanine
g={2}, --g-GLY-Glycine
h={10}, --h-HIS-Histidine
i={8}, --i-ILE-IsoLeucine
k={9}, --k-LYS-Lysine
l={6}, --l-LEU-Leucine
m={8}, --m-MET-Methionine
n={6}, --n-ASN-Asparagine
p={6}, --p-PRO-Proline
q={7}, --q-GLN-Glutamine
r={9}, --r-ARG-Argenine
s={6}, --s-SER-Serine
t={6}, --t-THR-Threonine
v={7}, --v-VAL-Valine
w={14}, --w-TRP-Tryptophan
y={12} --y-TYR-Tyrosine
}
function atomIndex(segment_index)
local aminoAcid = structure.GetAminoAcid(segment_index)
-- Check if aminoAcid exists in atom_indices
if atom_indices[aminoAcid] == nil then
return 5 -- Use beta carbon instead (first atom of the sidechain)
end
local AtomIndexOfTipOfSideChain = atom_indices[aminoAcid][1] --returns the number value from a aminoacid letter code.
return AtomIndexOfTipOfSideChain
end
function main()
local initialScore = current.GetScore()
local lastBS = minBS
local qsc = Score()
save.Quicksave(1)
p('Starting Hydro Puller, Start score: ' .. round(qsc))
x = 0
while x < segCnt do
x=x+1
while true do --random hydro segment
if structure.IsHydrophobic(x) then
break
end
x=x+1
if x>segCnt then
break
end
end
if x>segCnt then
break
end
local ls = Score()
local loss = round(ls * (maxLoss / 100))
p(' pulling seg: ' .. x)
MakeBands(x)
p('Made ' .. band.GetCount() .. ' bands, pulling until loss of ' .. loss .. ' pts.')
-- selection.SelectAll()
CI(pullingCI)
recentbest.Save()
for str = lastBS, maxBS, 0.07 do --search enough band strenght to move
recentbest.Restore() --because sometimes it makes points during pull :D
local ss = Score()
bandstr(str)
structure.WiggleAll(1, true, false)
if ss - Score() > loss then
lastBS = str - 0.1
if lastBS < minBS then
lastBS = minBS
end
break
end
end
band.DeleteAll()
SaveRB() --because sometimes it missing fractions
p('Stabilizing...')
CI(1)
recentbest.Save() --after pulling
qStab()
if Score() > ls + doFuze then
SaveBest()
Fuze(4)
end
SaveBest()
save.Quickload(1) --load best state
p('Current score: ' .. round(Score()) .. ' Total gain: ' .. Total_gain())
end
p('Total gain: ' .. Total_gain())
-- repeat main if score inproved
if current.GetScore() > initialScore then
main()
end
if ending_print_once then
ending_print()
end
end
-- end of script
-- start of standard Bravo Template
function Total_gain()
return (best_score-starting_score)
end
-- Function to check and update the best score
function check_and_update_score(segment)
local new_score = current.GetScore()
if new_score > best_score then
gain = new_score - best_score
best_score = new_score
save.Quicksave(1)
if gain > 0.001 then-- was printing pointless gains with to much clutter. still want to keep score improvement though
print(" Seg: " .. segment .. " Score: " .. best_score .. " Gain: " .. gain)
end
return -- Score improved
else
save.Quickload(1)
return -- Score did not improve
end
end
ending_print_once = true
function ending_print()
if ending_print_once then
-- Print the best score and total gain
local total_gain = best_score - starting_score
print("Best score: " .. best_score)
print("Total gain: " .. total_gain)
ending_print_once = false
end
end
-- Error handler function
function error_handler(err)
print("Error: " .. err)
check_and_update_score(0) --error can't pass segment info so i use "0"
ending_print()
return
end
xpcall(main, error_handler)