Profile
- Name
- Ligand_Optimize_v2.1
- ID
- 109351
- Shared with
- Public
- Parent
- Ligand_Optimize_v2
- Children
- None
- Created on
- February 03, 2026 at 06:57 AM UTC
- Updated on
- February 03, 2026 at 06:57 AM UTC
- Description
Best for
Code
--[[
Ligand Binding Pocket Optimizer v1.0
Optimizes protein residues around ligands by:
- Finding residues near ligands
- Testing different amino acid types (if mutable)
- Testing rotamers for nearby residues
- V2
Expanded search range
Expanded wiggle range
]]--
local CONFIG = {
SEARCH_RADIUS = 8.0, -- Angstroms around ligand
WIGGLE_ITERATIONS = 15,
MUTATE_ITERATIONS = 2,
BEST_SLOT = 8
}
function getScore()
return current.GetEnergyScore()
end
function findLigands()
local ligands = {}
for i = 1, structure.GetCount() do
if structure.GetSecondaryStructure(i) == "M" then
table.insert(ligands, i)
end
end
return ligands
end
function findNearbyResidues(ligandSeg, radius)
local nearby = {}
local totalSegs = structure.GetCount()
for seg = 1, totalSegs do
if structure.GetSecondaryStructure(seg) ~= "M" then
local dist = structure.GetDistance(ligandSeg, seg)
if dist < radius then
table.insert(nearby, {seg = seg, dist = dist})
end
end
end
table.sort(nearby, function(a, b) return a.dist < b.dist end)
return nearby
end
function optimizeRotamers(segments)
local improvements = 0
save.Quicksave(CONFIG.BEST_SLOT)
local bestScore = getScore()
for _, segData in ipairs(segments) do
local seg = segData.seg
local rotCount = rotamer.GetCount(seg)
if rotCount > 1 then
for rotIdx = 1, rotCount do
rotamer.SetRotamer(seg, rotIdx)
structure.ShakeSidechainsAll(1)
structure.WiggleAll(CONFIG.WIGGLE_ITERATIONS)
if getScore() > bestScore then
bestScore = getScore()
improvements = improvements + 1
save.Quicksave(CONFIG.BEST_SLOT)
print(string.format("Seg %d rot %d: %.3f", seg, rotIdx, bestScore))
else
save.Quickload(CONFIG.BEST_SLOT)
end
end
end
end
return improvements
end
function mutatePocket(segments)
local hasMutables = false
-- Check if any are mutable
for _, segData in ipairs(segments) do
if structure.IsMutable(segData.seg) then
hasMutables = true
break
end
end
if not hasMutables then
print("No mutable residues in binding pocket")
return 0
end
local startScore = getScore()
save.Quicksave(CONFIG.BEST_SLOT)
selection.DeselectAll()
for _, segData in ipairs(segments) do
if structure.IsMutable(segData.seg) then
selection.Select(segData.seg)
end
end
structure.MutateSidechainsSelected(CONFIG.MUTATE_ITERATIONS)
structure.WiggleAll(CONFIG.WIGGLE_ITERATIONS)
local gain = getScore() - startScore
if gain > 0 then
save.Quicksave(CONFIG.BEST_SLOT)
print(string.format("Mutation gain: +%.3f", gain))
return 1
else
save.Quickload(CONFIG.BEST_SLOT)
return 0
end
end
function optimizeLigandPocket()
local ligands = findLigands()
if #ligands == 0 then
print("No ligands found")
return
end
print(string.format("Found %d ligand(s)", #ligands))
local startScore = getScore()
print(string.format("Starting score: %.3f", startScore))
for _, ligandSeg in ipairs(ligands) do
print(string.format("\nOptimizing pocket around ligand %d", ligandSeg))
local nearby = findNearbyResidues(ligandSeg, CONFIG.SEARCH_RADIUS)
print(string.format("Found %d residues within %.1fÅ", #nearby, CONFIG.SEARCH_RADIUS))
-- Show nearby residues
if #nearby > 0 then
local segList = {}
for i = 1, math.min(10, #nearby) do
table.insert(segList, nearby[i].seg)
end
print("Closest: " .. table.concat(segList, ", "))
end
-- Try mutations if available
mutatePocket(nearby)
-- Optimize rotamers
local improvements = optimizeRotamers(nearby)
print(string.format("Rotamer improvements: %d", improvements))
end
-- Final polish
print("\nFinal wiggle...")
structure.WiggleAll(CONFIG.WIGGLE_ITERATIONS * 2)
local finalScore = getScore()
local totalGain = finalScore - startScore
print(string.format("\n=== Results ==="))
print(string.format("Start: %.5f", startScore))
print(string.format("Final: %.5f", finalScore))
print(string.format("Gain: %.5f", totalGain))
save.Quicksave(3)
end
function requestSettings()
local ask = dialog.CreateDialog("Ligand Pocket Optimizer")
ask.radius = dialog.AddSlider("Search Radius (Å)",
CONFIG.SEARCH_RADIUS, 1, 500, 1)
ask.wiggle = dialog.AddSlider("Wiggle Iterations",
CONFIG.WIGGLE_ITERATIONS, 1, 500, 0)
ask.OK = dialog.AddButton("Start", 1)
ask.Cancel = dialog.AddButton("Cancel", 0)
if dialog.Show(ask) > 0 then
CONFIG.SEARCH_RADIUS = ask.radius.value
CONFIG.WIGGLE_ITERATIONS = ask.wiggle.value
return true
end
return false
end
function main()
if not requestSettings() then
print("Cancelled")
return
end
behavior.SetClashImportance(1)
save.Quicksave(1)
optimizeLigandPocket()
end
function cleanup(err)
print("Error: " .. tostring(err))
save.Quickload(1)
end
xpcall(main, cleanup)