Icon representing a recipe

Recipe: bandsome2

created by Wipf

Profile


Name
bandsome2
ID
103181
Shared with
Public
Parent
bandsome
Children
Created on
November 21, 2019 at 13:12 PM UTC
Updated on
November 21, 2019 at 13:12 PM UTC
Description

Interactively place bands between specific atoms in protein.
Version 2 handles the atom numbers more robustly.

Best for


Code


-- -- bandsome: interactively place bands between specific atoms in protein -- -- by jeff101 8/11/12 -- edited by Wipf -- function Main() -- recipe information in global variables RecipeName = "bandsome" RecipeVersion = "2" Recipe = RecipeName .. "" .. RecipeVersion -- set logger variable wipf.logger = print local residue_count = structure.GetCount() local band_count = band.GetCount() print(string.format( '%s begins at %s on\n puzzle %s\n with puzzle ID %d, %d residues, %d bands,\n and score %.3f.', Recipe, os.date(), puzzle.GetName(), puzzle.GetPuzzleID(), residue_count, band_count, current.GetScore() )) local symmetry_copy_count if nil ~= structure.GetSymCount then symmetry_copy_count = structure.GetSymCount() else -- Foldit version older than devprev 2019-Okt-29 -- For testing purposes the count can be set to any number here, it won't crash the recipe. symmetry_copy_count = 0 end ---- create dialog with default values ---- local from_residue = 36 local to_residue = 72 if from_residue > residue_count then from_residue = 1 end if to_residue > residue_count then to_residue = residue_count end local ask=dialog.CreateDialog( Recipe .. " - add band" ) ask.message = dialog.AddLabel("") --ask.top_separator = dialog.AddLabel("") -- display this text if and only if the monomer slider is available if symmetry_copy_count > 0 then ask.label_w1 = dialog.AddLabel("The first residue is always on the main monomer.") end ask.from_residue = dialog.AddSlider("from residue",from_residue,1,residue_count,0) ask.from_atom = dialog.AddLabel("from atom") ask.separator1 = dialog.AddLabel("") -- If there are no symmetric copies, the slider would have a value range from 0 to 0, -- which foldit's sliders don't like. Thus this will only be there on symmetry puzzles. ---- Wipf, 2019-Nov-09 if symmetry_copy_count > 0 then ask.to_monomer = dialog.AddSlider( "to monomer", 0, 0,symmetry_copy_count, 0 ) ask.label_w2 = dialog.AddLabel( "monomer 0 is the main monomer,\nthe others are its symmetric copies" ) end ask.to_residue = dialog.AddSlider("to residue",to_residue,1,residue_count,0) ask.to_atom = dialog.AddLabel("to atom") ask.separator2 = dialog.AddLabel("") ask.length = dialog.AddSlider( "goal length", 2, 0,10, 1 ) ask.strength = dialog.AddSlider( "strength", 10, 0,10, 1 ) ask.bottom_separator = dialog.AddLabel("") ask.keeplast=dialog.AddSlider( "keep last: ", 0, -1,2,0 ) ask.Label7a=dialog.AddLabel("-1: remove all existing bands\n 0: replace previous band") --ask.Label7a=dialog.AddLabel("-1: remove all existing bands") --ask.Label7b=dialog.AddLabel(" 0: replace previous band") ask.Label7c=dialog.AddLabel(" 1: keep previous band") ask.Label7d=dialog.AddLabel(" 2: quit now without adding a new band\n ") -- the space in the second line prevents the second line from being ignored, making sure the first line is raised up a little bit --ask.Label7e=dialog.AddLabel("") ask.label_w2a = dialog.AddLabel("Different residues have different numbers of atoms.") ask.label_w2b = dialog.AddLabel("Use the 'update' button after selecting the residues\nto update the atom slider ranges.") ask.update = dialog.AddButton("update", 2) ask.OK = dialog.AddButton("OK", 1) function log_to_dialog( message ) print(message) ask.message.label = message end wipf.logger = log_to_dialog -- 0 is always the alpha-carbon local to_monomer local from_atom = 0 local to_atom = 0 local band_number = 0 local band_length local band_strength ---- get input values ---- while true do -- make sure atom numbers are in range local from_atom_count=structure.GetAtomCount(from_residue) local to_atom_count=structure.GetAtomCount( to_residue) if from_atom > from_atom_count then from_atom = from_atom_count end if to_atom > to_atom_count then to_atom = to_atom_count end ---- update dialog ---- ask.from_atom = dialog.AddSlider( "from atom", from_atom, 0, from_atom_count, 0 ) ask.to_atom = dialog.AddSlider( "to atom", to_atom, 0, to_atom_count, 0 ) ---- display dialog and read the new values ---- local answer = dialog.Show(ask) ask.message.label = "" if 0 == answer then -- user closed the dialog using the red cross at the top corner break end if symmetry_copy_count > 0 then to_monomer = ask.to_monomer.value end from_residue = ask.from_residue.value to_residue = ask.to_residue.value from_atom = ask.from_atom.value to_atom = ask.to_atom.value band_length = ask.length.value band_strength = ask.strength.value local keeplast = ask.keeplast.value -- update button: skip band deletion and creation if 2 ~= answer then ---- delete / add bands ---- if keeplast== -1 then print('Deleting all '..band.GetCount()..' previous bands.') band.DeleteAll() elseif keeplast==0 then if band_number > 0 then print('Deleting band '..band_number..'...') band.Delete( band_number ) print(tostring(band.GetCount())..' bands remaining.') end elseif keeplast == 2 then break -- this will quit end local aa1=structure.GetAminoAcid(from_residue) local aa2=structure.GetAminoAcid(to_residue) local ss1=structure.GetSecondaryStructure(from_residue) local ss2=structure.GetSecondaryStructure(to_residue) print('Adding band between atom '..from_atom..' on '..aa1..from_residue..' ('..ss1..')\n and atom '..to_atom..' on '..aa2..to_residue..' ('..ss2..') with strength '..band_strength..',\n goal length '..band_length..'.') band_number = wipf.AddBandBetweenSegments( from_residue, to_residue, from_atom, to_atom, to_monomer ) if band_number > 0 then band.SetGoalLength(band_number,band_length) -- 3.5 is default band length band.SetStrength(band_number,band_strength) -- 10 is max, 1 is default print(string.format( 'Band %d added, its present length is %.2f.', band_number, band.GetLength(band_number) )) else print('Failed to add new band. Still have '..band.GetCount()..' bands.') end end -- if (update button) end -- while Cleanup() end -- Main() -- table for Wipf's functions and variables wipf={} -- -- safety wrapper around band.AddBetweenSegments to prevent -- the game from hanging up -- function wipf.AddBandBetweenSegments( from_segment, to_segment, from_atom, to_atom, to_symmetric_copy ) -- check atom indices if nil ~= from_atom then if from_atom < 0 or from_atom > structure.GetAtomCount(from_segment) then if nil ~= wipf.logger then wipf.logger(string.format( "Invalid atom index %d for residue %d (it has %d atoms)!", from_atom, from_segment, structure.GetAtomCount(from_segment) )) end return 0 end end if nil ~= to_atom then if to_atom < 0 or to_atom > structure.GetAtomCount(to_segment) then if nil ~= wipf.logger then wipf.logger(string.format( "Invalid atom index %d for residue %d (it has %d atoms)!", to_atom, to_segment, structure.GetAtomCount(to_segment) )) end return 0 end end -- add band if nil ~= structure.GetSymCount then -- devprev only currently (2019-Nov-10) return band.AddBetweenSegments( from_segment, to_segment, from_atom, to_atom, to_symmetric_copy ) else return band.AddBetweenSegments( from_segment, to_segment, from_atom, to_atom ) end end -- -- rounds to nearest integer -- function round(val) local res=math.floor(val) if val-res>=0.5 then res=res+1 end return res end -- -- cleanup routine to be called whenever the recipe terminates, -- optionally with an error message -- function Cleanup( error ) -- Model 120: error reporting local reason, start, stop, line, msg if nil == error then reason = "complete" else start, stop, line, msg = error:find( ":(%d+):%s()" ) if msg ~= nil then error = error:sub( msg ) end if error:find( "Cancelled" ) ~= nil then reason = "cancelled" else reason = "error" print( "---- recipe error ----" ) print( "Line number: " .. line ) print( "Error message: " .. error ) end end -- Model 100: report recipe, termination reason, puzzle and track print( "---- terminated: " .. reason .. " ----" ) print('Ending with '..band.GetCount()..' bands for '..structure.GetCount()..' residues.') print( "Puzzle: " .. puzzle.GetName() ) print( "Track: " .. ui.GetTrackName() ) print( "Recipe: " .. Recipe ) print('All done at '..os.date()..'.') print( "==== END ====" ) end -- start main script and catch if it crashes -- according to rule 'Model 000' xpcall(Main,Cleanup)

Comments