Icon representing a recipe

Recipe: SelectoPro v1.1

created by LociOiling

Profile


Name
SelectoPro v1.1
ID
102521
Shared with
Public
Parent
None
Children
Created on
January 24, 2022 at 01:10 AM UTC
Updated on
January 24, 2022 at 01:10 AM UTC
Description

Select segments if they are (or aren't) mutable, frozen, locked, hydrophobic, or hydrophilic. If "core" objectives found, select core, boundary, or surface segments. Optionally, preserve existing selections.

Best for


Code


--[[ SelectoPro select segments based on criteria v1.0 - LociOiling - 2017/10/31 -- select mutable, locked, frozen, hydrophobic, hydrophilic, etc. v1.1 - LociOiling - 2022/01/23 -- select monomer or complex core, boundary, surface ]]-- -- -- globals section -- Recipe = "SelectoPro" Version = "1.1" ReVersion = Recipe .. " v" .. Version segCnt = 0 segCnt2 = 0 objectives = 0 coreSimplex = false simplexMap = {} coreComplex = false complexMap = {} sMutable = false sLocked = false sFrozen = false sPhobic = false sPhilic = false sSimplex = false sComplex = false tSimplex = "C" tComplex = "C" sKeep = false sInvert = false -- -- getCoreMap - get a table of core status by segment number -- -- Use filter.GetData to retrieve core status of each segment. -- Convert filter.GetData into a friendlier format. -- -- arguments: -- -- filtername - "Core Existence" or a related name -- segc - number of segments -- -- returns: -- -- table indexed by segment number, 1 = core, 0 = boundary, -1 = surface -- function getCoreMap ( filtername, segc ) local coretab = {} local datum = filter.GetData ( filtername ) local valz = 0 for ii = 1, segc do local key = tostring ( ii ) local val = datum [ key ] if val ~= nil then valz = valz + 1 end coretab [ #coretab + 1 ] = val end return coretab end function getCoreType ( intype ) local coreType = { C = 1, B = 0, S = -1, } return coreType [ intype ] end function getCoreName ( intype ) local coreName = { C = "core", B = "boundary", S = "surface", } return coreName [ intype ] end function GetParameters () local uerror = "" local rc repeat local d = dialog.CreateDialog ( ReVersion ) d.l0 = dialog.AddLabel ( "Select segments if..." ) d.sMutable = dialog.AddCheckbox ( "Mutable?", sMutable ) d.sLocked = dialog.AddCheckbox ( "Locked?", sLocked ) d.sFrozen = dialog.AddCheckbox ( "Frozen?", sFrozen ) d.sPhobic = dialog.AddCheckbox ( "Hydrophobic?", sPhobic ) d.sPhilic = dialog.AddCheckbox ( "Hydrophilic?", sPhilic ) if coreSimplex then d.sSimplex = dialog.AddCheckbox ( "Core: monomer (Core, Boundary, Surface)?", sSimplex ) d.tSimplex = dialog.AddTextbox ( "C/B/S", tSimplex ) end if coreComplex then d.sComplex = dialog.AddCheckbox ( "Core: complex (Core, Boundary, Surface)?", sComplex ) d.tComplex = dialog.AddTextbox ( "C/B/S", tComplex ) end d.l5 = dialog.AddLabel ( "" ) d.sKeep = dialog.AddCheckbox ( "Keep existing selections?", sKeep ) d.sInvert = dialog.AddCheckbox ( "Invert new selections?", sInvert ) if uerror:len () > 0 then d.lerr1 = dialog.AddLabel ( "" ) d.lerr2 = dialog.AddLabel ( "ERROR: " .. uerror ) end d.ok = dialog.AddButton ( "OK" , 1 ) d.cancel = dialog.AddButton ( "Cancel" , 0 ) rc = dialog.Show ( d ) uerror = "" if rc > 0 then sMutable = d.sMutable.value sLocked = d.sLocked.value sFrozen = d.sFrozen.value sPhobic = d.sPhobic.value sPhilic = d.sPhilic.value if coreSimplex then sSimplex = d.sSimplex.value if sSimplex then tSimplex = d.tSimplex.value if tSimplex:len () > 1 then tSimplex = tSimplex:sub ( 1, 1 ) end tSimplex = tSimplex:upper () if getCoreType ( tSimplex ) == nil then uerror = "invalid monomer core type \"" .. tSimplex .. "\" entered" end end end if coreComplex then sComplex = d.sComplex.value if sComplex then tComplex = d.tComplex.value if tComplex:len () > 1 then tComplex = tComplex:sub ( 1, 1 ) end tComplex = tComplex:upper () if getCoreType ( tComplex ) == nil then uerror = "invalid complex core type \"" .. tComplex .. "\" entered" end end end sKeep = d.sKeep.value sInvert = d.sInvert.value end until rc < 0 or uerror:len () == 0 return rc end function Init () segCnt = structure.GetCount() segCnt2 = segCnt while structure.GetSecondaryStructure ( segCnt2 ) == "M" do segCnt2 = segCnt2 - 1 end objectives = filter.GetNames () for ii = 1, #objectives do if filter.IsEnabled ( objectives [ ii ] ) then if objectives [ ii ] == "Core Existence" or objectives [ ii ] == "Core Existence: Monomer" then coreSimplex = true simplexMap = getCoreMap ( objectives [ ii ], segCnt2 ) elseif objectives [ ii ] == "Core: Complex" then coreComplex = true complexMap = getCoreMap ( objectives [ ii ], segCnt2 ) end end end end function main () Init () if not GetParameters () then return end print ( ReVersion ) print ( "Puzzle: " .. puzzle.GetName () ) print ( "Track: " .. ui.GetTrackName () ) print ( "options:" ) if sMutable then print ( "select mutables" ) end if sLocked then print ( "select locked" ) end if sFrozen then print ( "select frozen" ) end if sPhobic then print ( "select hyrdophobics" ) end if sPhilic then print ( "select hydrophilics" ) end if sSimplex then print ( "select monomer " .. getCoreName ( tSimplex ) ) end if sComplex then print ( "select monomer " .. getCoreName ( tComplex ) ) end if sKeep then print ( "keep existing selections" ) end if sInvert then print ( "invert new selections" ) end print ( "--" ) -- -- do it -- local sels = 0 if not sKeep then selection.DeselectAll () print ( "existing selections cleared" ) else for ii = 1, segCnt2 do if selection.IsSelected ( ii ) then sels = sels + 1 end end print ( sels .. " existing selections" ) end local cnt = 0 local errs = 0 for ii = 1, segCnt2 do local sellit = false if sMutable and structure.IsMutable ( ii ) and not sInvert then sellit = true end if sMutable and not structure.IsMutable ( ii ) and sInvert then sellit = true end if sLocked and structure.IsLocked ( ii ) and not sInvert then sellit = true end if sLocked and not structure.IsLocked ( ii ) and sInvert then sellit = true end if sFrozen and freeze.IsFrozen ( ii ) and not sInvert then sellit = true end if sFrozen and not freeze.IsFrozen ( ii ) and sInvert then sellit = true end if sPhobic and structure.IsHydrophobic ( ii ) and not sInvert then sellit = true end if sPhobic and not structure.IsHydrophobic ( ii ) and sInvert then sellit = true end if sPhilic and not structure.IsHydrophobic ( ii ) and not sInvert then sellit = true end if sPhilic and structure.IsHydrophobic ( ii ) and sInvert then sellit = true end if sSimplex and simplexMap [ ii ] == getCoreType ( tSimplex ) and not sInvert then sellit = true end if sSimplex and simplexMap [ ii ] ~= getCoreType ( tSimplex ) and sInvert then sellit = true end if sComplex and complexMap [ ii ] == getCoreType ( tComplex ) and not sInvert then sellit = true end if sComplex and complexMap [ ii ] ~= getCoreType ( tComplex ) and sInvert then sellit = true end if sellit and not selection.IsSelected ( ii ) then selection.Select ( ii ) if selection.IsSelected ( ii ) then cnt = cnt + 1 else errs = errs + 1 end end end print ( cnt .. " selections added" ) if errs > 0 then print ( errs .. " selection errors (locked segments, etc.) " ) end if segCnt2 ~= segCnt then print ( segCnt - segCnt2 .. " ligand segments not included" ) end print ( sels + cnt .. " total segements selected" ) cleanup () end function cleanup ( errmsg ) print ( "---" ) local reason local start, stop, line, msg if errmsg == nil then reason = "complete" else -- -- civilized error reporting, -- thanks to Bruno K. and Jean-Bob -- start, stop, line, msg = errmsg:find ( ":(%d+):%s()" ) if msg ~= nil then errmsg = errmsg:sub ( msg, #errmsg ) end if errmsg:find ( "Cancelled" ) ~= nil then reason = "cancelled" else reason = "error" end end print ( ReVersion .. " " .. reason ) print ( "Puzzle: " .. puzzle.GetName () ) print ( "Track: " .. ui.GetTrackName () ) if reason == "error" then print ( "Unexpected error detected" ) print ( "Error line: " .. line ) print ( "Error: \"" .. errmsg .. "\"" ) end end xpcall ( main , cleanup )

Comments


LociOiling Lv 1

SelectoPro works with the selection interface. It can select segments based on whether they are mutable, frozen, locked, hydrophobic, or hydrophilic.

SelectoPro can get around limitations on certain puzzles. For example, on puzzle 1443, the structures tool is not available if all segments are selected. The tool only appears when mutable segments are selected. The "mutable" option of SelectoPro lets you use the auto-structures option on all mutable segments at once.

The recipe selects segments if any of the specified options apply. In other words, a logical OR is applied. So if "mutable" and "hydrophobic" are specified, a segment is selected if it's either mutable or hydrophobic, or both.

The recipe clears existing selections by default. The "keep existing selections" option changes this behavior.

The "invert new selections" option flips the selection logic. In other words, a logical NOT is applied. For example, if "mutable" and "invert new selections" are specified, the recipe selects all segments that are not mutable. (The NOT is applied to each property individually, instead of all specified properties as a group.)

The recipe counts how many segments it selects, and reports the count in the scriptlog. If "keep existing selections" is specified, only new selections are counted.

Not all segments can be selected. For example, on puzzle 1440, many segments have locked backbone. These segments cannot be selected. If the "locked" option is specified, these segments are counted as an error. The "locked" option may be more useful if "invert new selections" is specified.

Each time it selects a segment, the recipe checks to see whether the segment is selected. Segments which fail this test are counted as selection errors. The total number of selection errors is reported in the scriptlog.

The segment properties are based on corresponding functions in the Foldit Lua Interface. For example, the Lua function structure.IsMutable determines whether a segment is mutable, and is the basis of the "mutable" option.

The "frozen" option selects segments based on whether their backbone is frozen. There is no option to select segments with frozen sidechains.

The "hydrophilic" option is a special case. The Foldit Lua interface provides a function to check for a hydrophobic segment (structure.IsHydrophobic), but there's not a separate function for hydrophilics. Instead, the definition of "hydrophilic" is "not hydrophobic". The recipe's "hydrophilic" option is based on this logic.

LociOiling Lv 1

If the objectives "Core Existence" or "Core Existence: Monomer" and "Core: Complex" are present and enabled, they can be used to make selections.

For these objectives, the function filter.GetData returns a table which indicates whether each segment is core, boundary, or surface. The recipe can have two of these checkboxes, one for the monomer objective, found in many design puzzles, and one for the complex objective, found in symmetry puzzles.

By default, the core segments are selected when one of the checkboxes is checked. The default selection can changed in the "C/B/S" box, with "C" for core, "B" for boundary, and "S" for surface. (Only the first letter entered counts, and it's converted to upper case.)

The recipe demonstrates use of filter.GetData, converting the returned table into a more usable format.