Icon representing a recipe

Recipe: Ligand_Optimize_v2

created by Fasodankfds

Profile


Name
Ligand_Optimize_v2
ID
109350
Shared with
Public
Parent
Ligand_Optimize_v1
Children
Created on
February 03, 2026 at 06:52 AM UTC
Updated on
February 03, 2026 at 06:54 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: %.3f", startScore)) print(string.format("Final: %.3f", finalScore)) print(string.format("Gain: %.3f", totalGain)) save.Quicksave(3) end function requestSettings() local ask = dialog.CreateDialog("Ligand Pocket Optimizer") ask.radius = dialog.AddSlider("Search Radius (Å)", CONFIG.SEARCH_RADIUS, 1, 5000, 1) ask.wiggle = dialog.AddSlider("Wiggle Iterations", CONFIG.WIGGLE_ITERATIONS, 1, 10000, 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)

Comments