Icon representing a recipe

Recipe: Make 4 Helix Structures

created by Chris Klassen

Profile


Name
Make 4 Helix Structures
ID
103694
Shared with
Public
Parent
None
Children
None
Created on
July 10, 2020 at 14:50 PM UTC
Updated on
July 10, 2020 at 14:50 PM UTC
Description

This will make four crude helix structures.

Best for


Code


-- How to use this script to make some helix structure on one side and some sheet on the other. -- You can specify zero sheets if you only want helix structures. -- Step 1: Run the script and set pass to 1 -- This will start the puzzle over and try to make the helix and sheet structures -- -- Step 2: Go to each of the secondary structures and do "Idealize SS". This can't -- be done in the script for whatever reason, so you'll need to do this by hand. -- If this is a docking puzzle, you might want to move the user -- portion away from docking point for now to avoid pointless collisions. -- If you are not setting the helix structures to be all A's, then you may want to -- wiggle a bit just to get rid of clashes inside the helix structures themselves. -- -- Step 3: Run this script and set pass to 2 -- This freeze the secondary structures and setup bands. If wiggle is true, it will try to -- wiggle into place as it sets the bands. -- -- Step 4: Run wiggle until a shape forms with the two helix structures on one side and the -- sheets on the other. -- Sometimes this structure will not form as the secondary structures get in each other's way. -- You might need to do some manual pulling, or selective enabling/disabling bands -- or simply try again. -- -- Step 5: Run whatever else you want to improve your score. Usually a mutate run and some stabilization. -- At some point unfreeze the secondary structures so they can change shape too. -- -- Note: You can always run the script with pass set to 2 and wiggle off to setup the bonds and freezing again. k_cut_points = false start_time = 0 function FindFirstAvailable() for seg_idx = 1, structure.GetCount() do if not structure.IsLocked(seg_idx) then return seg_idx end end return nil end function IdealizeAll() selection.SelectAll() structure.IdealizeSelected() selection.DeselectAll() end function FreezeRange(from_seg_idx, to_seg_idx) selection.DeselectAll() for seg_idx = from_seg_idx, to_seg_idx do selection.Select(seg_idx) end freeze.FreezeSelected(true, true) selection.DeselectAll() end function UnfreezeRange(from_seg_idx, to_seg_idx) selection.DeselectAll() for seg_idx = from_seg_idx, to_seg_idx do selection.Select(seg_idx) end freeze.UnfreezeSelected(true, true) selection.DeselectAll() end function SetSecondaryStructureRange(ss, from_seg_idx, to_seg_idx) selection.DeselectAll() for seg_idx = from_seg_idx, to_seg_idx do selection.Select(seg_idx) end structure.SetSecondaryStructureSelected (ss) selection.DeselectAll() end function SetAminoAcidRange(aa1, from_seg_idx, to_seg_idx) selection.DeselectAll() for seg_idx = from_seg_idx, to_seg_idx do selection.Select(seg_idx) end structure.SetAminoAcidSelected (aa1) selection.DeselectAll() end function CountResidues() local n_residues = structure.GetCount() local user_residue_start = FindFirstAvailable() local user_residue_count = structure.GetCount() - user_residue_start + 1 return user_residue_count end function MakeMultipleSSTable(ss_type, ss_count, loop_size, start_idx, residue_count) local ss = {} local loop = {} if (ss_count < 1) then return ss, loop end local non_end_loops = ss_count - 1 -- print("Between " .. ss_type .. " loop count " .. non_end_loops) local length_non_end_loops = non_end_loops * loop_size -- print("Between " .. ss_type .. " loops will be " .. length_non_end_loops .. " residues") ss_size = math.floor((residue_count - length_non_end_loops) / ss_count) print("Make " .. ss_type .. " of length " .. ss_size) local last_idx = start_idx - 1 for ss_idx = 1, ss_count do if ss_idx > 1 then AddLoopToTable(loop, last_idx + 1, loop_size) last_idx = last_idx + loop_size end local this_ss = {start = last_idx + 1, finish = last_idx + ss_size} print(ss_type .. " start: " .. this_ss.start .. " finish: " .. this_ss.finish) table.insert(ss, this_ss) last_idx = this_ss.finish end return ss, loop end function AddEndLoopIfNeeded(loop, last_used_idx) local n_residues = structure.GetCount() if (last_used_idx < n_residues) then AddLoopToTable(loop, last_used_idx + 1, n_residues - last_used_idx) end end function MakeMultipleHelixTable(helix_count, loop_size, start_idx, residue_count) return MakeMultipleSSTable("Helix", helix_count, loop_size, start_idx, residue_count) end function MakeMultipleSheetTable(sheet_count, loop_size, start_idx, residue_count) return MakeMultipleSSTable("Sheet", sheet_count, loop_size, start_idx, residue_count) end function AddLoopToTable(loop_table, start_idx, loop_size) local this_loop = {start = start_idx, finish = start_idx + loop_size - 1} print("Loop start: " .. this_loop.start .. " finish: " .. this_loop.finish) table.insert(loop_table, this_loop) end function MakeMultipleSS(helix, sheets, loop, helix_amino, loop_amino, sheet_edge_amino, sheet_middle_amino) print("Start puzzle over") puzzle.StartOver() for idx = 1, #helix do local this_helix = helix[idx] print("Helix start: " .. this_helix.start .. " finish: " .. this_helix.finish) SetSecondaryStructureRange("H", this_helix.start, this_helix.finish) if (helix_amino ~= "") then print("Set Helix amino acids to " .. helix_amino) SetAminoAcidRange(helix_amino, this_helix.start, this_helix.finish) end end for idx = 1, #sheets do local this_sheet = sheets[idx] print("Sheet start: " .. this_sheet.start .. " finish: " .. this_sheet.finish) SetSecondaryStructureRange("E", this_sheet.start, this_sheet.finish) if (sheet_edge_amino ~= "") then print("Set Sheet edge amino acids to " .. sheet_edge_amino) structure.SetAminoAcid(this_sheet.start, sheet_edge_amino) structure.SetAminoAcid(this_sheet.finish, sheet_edge_amino) end if (sheet_middle_amino ~= "") then print("Set Sheet middle amino acids to " .. sheet_middle_amino) SetAminoAcidRange(sheet_middle_amino, this_sheet.start+1, this_sheet.finish-1) end end for idx = 1, #loop do print("Loop start: " .. loop[idx].start .. " finish: " .. loop[idx].finish) SetSecondaryStructureRange("L", loop[idx].start, loop[idx].finish) if (loop_amino ~= "") then print("Set Loop amino acids to " .. loop_amino) SetAminoAcidRange(loop_amino, loop[idx].start, loop[idx].finish) end end end function AddBand(name, start_idx, finish_idx, separation) print("Add " .. name .. " band") local band_idx = band.AddBetweenSegments(start_idx, finish_idx) print( "Band: " .. band_idx) band.SetGoalLength(band_idx, separation) band.SetStrength(band_idx, 5) end function WiggleSelected(from_seg_idx, to_seg_idx) selection.DeselectAll() for seg_idx = from_seg_idx, to_seg_idx do selection.Select(seg_idx) end structure.LocalWiggleSelected(5, true, false) end function PlaceBands(helix, sheets, wiggle) band.DeleteAll() local length_helix = structure.GetDistance(helix[1].start, helix[1].finish) local separation = length_helix --math.floor(length_helix * 2 / 3) local first_helix, second_helix for helix_idx = 1, #helix - 1 do first_helix = helix_idx second_helix = helix_idx + 1 AddBand("helix anchor", helix[first_helix].start, helix[second_helix].finish, separation) AddBand("helix end", helix[first_helix].finish, helix[second_helix].start, separation) if wiggle then WiggleSelected(helix[first_helix].finish, helix[second_helix].start) end end if (#sheets > 0) then AddBand("helix to sheet anchor", helix[#helix].start, sheets[1].finish, separation) AddBand("helix to sheet end", helix[#helix].finish, sheets[1].start, separation) for sheet_idx = 1, #sheets - 1 do first_sheet = sheet_idx second_sheet = sheet_idx + 1 AddBand("sheet anchor", sheets[first_sheet].start, sheets[second_sheet].finish, separation) AddBand("sheet end", sheets[first_sheet].finish, sheets[second_sheet].start, separation) if wiggle then WiggleSelected(sheets[first_sheet].finish, sheets[second_sheet].start) end end AddBand("sheet to helix anchor", sheets[#sheets].start, helix[1].start, separation) AddBand("helix to sheet end", sheets[#sheets].finish, helix[1].finish, separation) AddBand("cross band", helix[1].start, sheets[2].finish, separation) AddBand("cross band", helix[1].finish, sheets[2].start, separation) AddBand("cross band", helix[2].finish, sheets[2].finish, separation) AddBand("cross band", helix[2].start, sheets[2].start, separation) end -- corner_sep = math.sqrt(2) * separation end function FreezeSS(ss1, ss2) freeze.UnfreezeAll() for ss_idx = 1, #ss1 do FreezeRange(ss1[ss_idx].start, ss1[ss_idx].finish) end for ss_idx = 1, #ss2 do FreezeRange(ss2[ss_idx].start, ss2[ss_idx].finish) end end function MergeTable(table1, table2) local tableMerge = {} for idx = 1, #table1 do table.insert(tableMerge, table1[idx]) end for idx = 1, #table2 do table.insert(tableMerge, table2[idx]) end return tableMerge end function MakeCutPointsBetweenSS() local last_ss = "" for seg_idx = 1, structure.GetCount() do ss = structure.GetSecondaryStructure(seg_idx) -- Where secondary structures change, make a cut point if (last_ss ~= "" and ss ~= last_ss) then structure.InsertCut(seg_idx - 1) end last_ss = ss end end function MakeAnchorBand(origin, x_seg, y_seg) local rho = 0.01 -- Right where it is local theta = math.pi/2 -- In the reference plane local phi = 0 local band_idx = band.Add(origin, x_seg, y_seg, rho, theta, phi) band.SetGoalLength(band_idx, 0) band.SetStrength(band_idx, 10) -- Really hold it down end function MakeBandToGuideBand(seg_idx, guide_band_idx) local band_idx = band.AddToBandEndpoint(seg_idx, guide_band_idx) band.SetGoalLength(band_idx, 0) band.SetStrength(band_idx, 1) -- Not too strong --band.Delete(guide_band_idx) band.Disable(guide_band_idx) return band_idx end function WiggleIntoPlace(bands, wiggle_delta) wiggle_delta = wiggle_delta or 0.15 local delta local is_good local iter = 0 repeat iter = iter + 1 structure.WiggleAll(1, true, true) is_good = true for bidx = 1, #bands do local bnd = bands[bidx] print(" Bidx " .. bidx .. " Band " .. bnd) if (band.IsEnabled(bnd)) then delta = math.abs(band.GetLength(bnd) - band.GetGoalLength(bnd)) is_good = is_good and delta < wiggle_delta print(" Band " .. bnd .. " Delta " .. delta) end end print(" Iter is " .. iter .. " Delta is " .. delta .. " Goal is " .. wiggle_delta .. " Good is " .. (is_good and "true" or "false")) until is_good end function PlaceSS(ss1, ss2, wiggle) band.DeleteAll() local wiggle_iterations = 5 local start = ss1[1].start local finish = ss1[1].finish local y_seg = ss1[2].finish local desired_distance = structure.GetDistance(ss1[1].finish, ss1[2].start) -- Pin the start of the first helix MakeAnchorBand(start, finish, y_seg) -- Pin the other end MakeAnchorBand(finish, start, y_seg) local band_idx = band.Add(start, finish, y_seg, desired_distance, math.pi/2, math.pi/2) print ("Band A ".. band_idx) local band1 = MakeBandToGuideBand(ss1[2].finish, band_idx) print ("Band 1 ".. band1) band_idx = band.Add(finish, start, y_seg, desired_distance, math.pi/2, math.pi/2) print ("Band B ".. band_idx) local band2 = MakeBandToGuideBand(ss1[2].start, band_idx) print ("Band 2 ".. band2) if wiggle then structure.WiggleAll(wiggle_iterations) -- WiggleIntoPlace({band1, band2}, 1) FreezeRange(ss1[1].finish+1, ss1[2].start-1) end band_idx = band.Add(start, finish, y_seg, desired_distance * math.sqrt(2), 3*math.pi/4, math.pi/2) MakeBandToGuideBand(ss1[3].start, band_idx) band_idx = band.Add(finish, start, y_seg, desired_distance * math.sqrt(2), math.pi/4, math.pi/2) MakeBandToGuideBand(ss1[3].finish, band_idx) if wiggle then structure.WiggleAll(wiggle_iterations) FreezeRange(ss1[2].finish+1, ss1[3].start-1) end band_idx = band.Add(start, finish, y_seg, desired_distance, math.pi, math.pi/2) MakeBandToGuideBand(ss1[4].finish, band_idx) band_idx = band.Add(finish, start, y_seg, desired_distance, 0, math.pi/2) MakeBandToGuideBand(ss1[4].start, band_idx) if wiggle then structure.WiggleAll(wiggle_iterations * 2) UnfreezeRange(ss1[1].finish+1, ss1[2].start-1) UnfreezeRange(ss1[2].finish+1, ss1[3].start-1) end end function MakeTwistyBand(seg_idx, seg_start) -- Bases at 90/90 makes a helicopter local rho = 6.67 * (seg_idx - seg_start + 4) / 4 -- Starting angle out. Shrink for each later node. local start_theta = 15 -- 90 is the reference plane local theta_deg_rotate = start_theta / ((seg_idx-seg_start+2)/2) -- math.fmod(90 * seg_idx, 360) local theta_deg = theta_deg_rotate > 180 and theta_deg_rotate - 180 or theta_deg_rotate local theta = math.rad(theta_deg) -- Makes four around local base_phi = 90 -- 340 -- 90 produces a helicopter local phi_deg = math.fmod(base_phi + 90 * (seg_idx - seg_start), 360) -- local phi_deg = math.fmod(base_phi + 45 * (seg_idx - 1), 180) local phi = math.rad(phi_deg) print ("Twist band seg: " .. seg_idx .. " rho: " .. rho .. " theta: " .. theta_deg .. " phi: " .. phi_deg ) local ref_band_idx = band.Add(seg_start, seg_start+1, seg_start+2, rho, theta, phi, 1) band.SetStrength(ref_band_idx, 1) band.Disable(ref_band_idx) local band_idx = band.AddToBandEndpoint(seg_idx, ref_band_idx, 3) band.SetGoalLength(band_idx, 0) band.SetStrength(band_idx, 10) -- band.Delete(ref_band_idx) -- print("Disable twist band") -- band.Disable(band_idx) band.Enable(band_idx) return band_idx end -- Band on another atom to try to refine twist function MakeTwistyBandOtherAtom(seg_idx, seg_start) -- Bases at 90/90 makes a helicopter local rho = 6.67 * (seg_idx - seg_start + 4) / 4 - 2 -- Starting angle out. Shrink for each later node. local start_theta = 15 + 1 -- 90 is the reference plane local theta_deg_rotate = start_theta / ((seg_idx - seg_start + 2)/2) -- math.fmod(90 * seg_idx, 360) local theta_deg = theta_deg_rotate > 180 and theta_deg_rotate - 180 or theta_deg_rotate local theta = math.rad(theta_deg) -- Makes four around local base_phi = 90 -- 340 -- 90 produces a helicopter local phi_deg = math.fmod(base_phi + 90 * (seg_idx - seg_start), 360) -- local phi_deg = math.fmod(base_phi + 45 * (seg_idx - 1), 180) local phi = math.rad(phi_deg) print ("Twist band seg: " .. seg_idx .. " rho: " .. rho .. " theta: " .. theta_deg .. " phi: " .. phi_deg ) local ref_band_idx = band.Add(seg_start, seg_start+1, seg_start+2, rho, theta, phi, 1) band.SetStrength(ref_band_idx, 1) band.Disable(ref_band_idx) local band_idx = band.AddToBandEndpoint(seg_idx, ref_band_idx, 1) band.SetGoalLength(band_idx, 0) band.SetStrength(band_idx, 10) -- band.Delete(ref_band_idx) -- print("Disable twist band") -- band.Disable(band_idx) band.Enable(band_idx) return band_idx end function FreezeAllOutsideSS(ss) freeze.UnfreezeAll() if (ss.start > 1) then FreezeRange(1, ss.start-1) end FreezeRange(ss.finish, structure.GetCount()) end function TableConcat(t1,t2) for idx = 1, #t2 do table.insert(t1, t2[idx]) end return t1 end function MakeTwistyBands(helix) local twist_bands = {} local twist_band_alt = {} for seg_idx = helix.start, helix.finish do twist_bands[seg_idx] = MakeTwistyBand(seg_idx, helix.start) twist_band_alt[seg_idx] = MakeTwistyBandOtherAtom(seg_idx, helix.start) end local bands = TableConcat(twist_bands, twist_band_alt) return bands end function ShapeSS(helix, sheet) wiggle_iterations = 10 for ss_idx = 1, #helix do bands = MakeTwistyBands(helix[ss_idx]) FreezeAllOutsideSS(helix[ss_idx]) -- WiggleIntoPlace(bands) structure.WiggleAll(wiggle_iterations) band.DeleteAll() end freeze.UnfreezeAll() end -- Compute length by finding the length of each distinct SS -- Would be better if loops were treated as a sum of the lengths of each AA in the loop function ComputeLength() local first = FindFirstAvailable() local last_ss = "" local last_idx = first local seg_idx local length = 0 for seg_idx = first, structure.GetCount() do local ss = structure.GetSecondaryStructure(seg_idx) if last_ss ~= ss then local ss_length = structure.GetDistance(last_idx, seg_idx) print( "SS " .. ss .. " length " .. ss_length) length = length + ss_length last_idx = seg_idx last_ss = ss end end length = length + structure.GetDistance(last_idx, structure.GetCount()) return length end function IdealizeRange(from_seg_idx, to_seg_idx) print("Idealizing " .. from_seg_idx .. " to " .. to_seg_idx) selection.DeselectAll() for seg_idx = from_seg_idx, to_seg_idx do selection.Select(seg_idx) end structure.IdealizeSelected() selection.DeselectAll() end function IdealizeLoops() local first = FindFirstAvailable() local last_ss = "" local last_idx = first local seg_idx local length = 0 for seg_idx = first, structure.GetCount() do local ss = structure.GetSecondaryStructure(seg_idx) if last_ss ~= ss then if last_ss == "L" then IdealizeRange(last_idx, seg_idx) end last_idx = seg_idx last_ss = ss end end if last_ss == "L" then IdealizeRange(last_idx, structure.GetCount()) end end function SetPullStraightBands() local first = FindFirstAvailable() local distance_between_aas = structure.GetDistance(first, first+1) local current_length = structure.GetDistance(first, structure.GetCount()) local residue_count = structure.GetCount() - first local desired_length = ComputeLength() --residue_count * distance_between_aas -- If everything were straight local rho = (desired_length - current_length) / 2 print("Desired length " .. desired_length) print("Current length is " .. current_length) -- print("Distance between AA is " .. distance_between_aas) print("Rho is " .. rho) local theta = math.rad( 90 ) -- In the reference plane local phi = math.rad( 180 ) local band_idx = band.Add(first, structure.GetCount(), first+1, rho, theta, phi) band.SetGoalLength(band_idx, 0) band.SetStrength(band_idx, 1) band_idx = band.Add(structure.GetCount(), first, first+1, rho, theta, phi) band.SetGoalLength(band_idx, 0) band.SetStrength(band_idx, 1) end function PullStraight() band.DeleteAll() SetPullStraightBands() structure.WiggleAll(1, true, false) IdealizeLoops() band.DeleteAll() end function GetParameters () local dlog = dialog.CreateDialog("Make Basic Secondary Structure 1.1") dlog.lb1 = dialog.AddLabel("1 to make SS, idealize SS in UI, then 2 to shape SS.") dlog.pass = dialog.AddSlider("Pass", 0, 0, 3, 0) dlog.lb2 = dialog.AddLabel("0 - All, 1 = Build, 2 = Make SS, 3 = Shape") dlog.configuration = dialog.AddSlider("Configuration", 1, 1, 2, 0) dlog.lb3a = dialog.AddLabel("1 = 4 Helix Pack") -- 3 Helix Pack, 6 Helix Pack, 3 Helix + 2 Sheet. Others? dlog.loop_size = dialog.AddSlider("Loop Size", 3, 1, 10, 0) dlog.helix_amino = dialog.AddTextbox("Helix AA1", "A") dlog.lb4 = dialog.AddLabel("Helix loving AAs are M,A,L,E,K. Blank = don't change.") dlog.loop_amino = dialog.AddTextbox("Loop AA1", "G") dlog.lb5 = dialog.AddLabel("G is most flexible. A is also popular. Blank = don't change.") dlog.sheet_edge_amino = dialog.AddTextbox("Sheet Edge AA1", "P") dlog.sheet_middle_amino = dialog.AddTextbox("Sheet Middle AA1", "V") dlog.lb6 = dialog.AddLabel("Middle sheet options: V, I, T, Y, F, W") dlog.wiggle = dialog.AddCheckbox("Wiggle", true) dlog.ok = dialog.AddButton("OK", 1) dlog.cancel = dialog.AddButton("Cancel", 0) if (dialog.Show(dlog) > 0) then return dlog else return nil end end function ReadConfig(config_value) if (config_value > 0) then -- Change this to support more configurations return 4, 0 end return nil end function Main() start_time = os.time() local n_residues = structure.GetCount() print("Residue Count: " .. n_residues) local first_avail = FindFirstAvailable() print("First Editable Residue: " .. first_avail) parameters = GetParameters() if ( parameters == nil ) then return -- graceful exit end local helix_count, sheet_count = ReadConfig(parameters.configuration.value) local loop_size = parameters.loop_size.value local user_residue_count = CountResidues() print("User Residue Count: " .. user_residue_count) local helix_residue_count = sheet_count > 0 and math.floor((user_residue_count - loop_size) / 2) or user_residue_count print("Helix Residue Count: ".. helix_residue_count) local helix, loop = MakeMultipleHelixTable(helix_count, loop_size, first_avail, helix_residue_count) local last_helix_idx = #helix > 0 and helix[#helix].finish or 0 if (sheet_count > 0) then AddLoopToTable(loop, last_helix_idx + 1, loop_size) end local last_loop_idx = last_helix_idx + loop_size -- Now make sheet tables local sheet_residue_count = helix_residue_count local sheets, loop2 = MakeMultipleSheetTable(sheet_count, loop_size, last_loop_idx + 1, sheet_residue_count) local last_sheet_idx = #sheets > 0 and sheets[#sheets].finish or last_helix_idx loop = MergeTable(loop, loop2) AddEndLoopIfNeeded(loop, last_sheet_idx) local pass = parameters.pass.value if (pass == 1 or pass == 0) then print("Set Aminos") local helix_amino = parameters.helix_amino.value local loop_amino = parameters.loop_amino.value local sheet_edge_amino = parameters.sheet_edge_amino.value local sheet_middle_amino = parameters.sheet_middle_amino.value MakeMultipleSS(helix, sheets, loop, helix_amino, loop_amino, sheet_edge_amino, sheet_middle_amino) -- IdealizeAll() save.SaveSecondaryStructure() if (k_cut_points) then MakeCutPointsBetweenSS() end print("Set Aminos done") end if (pass == 2 or pass == 0) then print("Shape Secondary Structures") ShapeSS(helix, sheets) print("Shape Secondary Structures done") end if (pass == 3 or pass == 0) then print("Place Secondary Structures") -- FreezeSS(helix, sheets) -- PullStraight() PlaceSS(helix, sheets, parameters.wiggle.value) -- PlaceBands(helix, sheets, parameters.wiggle) print("Place Secondary Structures done") end print("End") Cleanup() end -- Cleanup for regular run or error function Cleanup() print( "Cleaning up" ) local end_time = os.time() print ( "Elapsed time: " .. os.difftime(end_time, start_time) .. " secs" ) end function ErrorHandler(str) print( "Error " .. str ) -- Do error handling here Cleanup() end --main () xpcall(Main, ErrorHandler)

Comments