Icon representing a recipe

Recipe: MicroIdealize 4.1.1

created by LociOiling

Profile


Name
MicroIdealize 4.1.1
ID
103222
Shared with
Public
Parent
MicroIdealize 4.0 test
Children
Created on
January 09, 2020 at 07:41 AM UTC
Updated on
January 09, 2020 at 07:41 AM UTC
Description

MI 4.1 now idealizes multiple lengths, and has a wiggle factor, similar to EDRW/DRemixW. MI 4.1.1 fixes a bug.

Best for


Code


--[[ MicroIdealize 4.1.1 Adapted from Microidealize 4.0 by spvincent, 2016/04/30 Microidealize 4.0 test - LociOiling 2017/12/18 * Track effect of idealizing locked or unlocked segments for aflatoxin and similar puzzles MicroIdealize 4.1 - 2019/12/02 - 2020/01/06 * add quasi-introspective trace for crashy puzzles * add adjustable lengths by popular demand * switch to modularized version of Timo code (SLT) * use named values in worklist and ideality tables * rework filter logic a little * added wiggle factor plus display/change wiggle power * seed the random number generator * improve score reporting a little MicroIdealize 4.1.1 - LociOiling - 2020/01/08 * ifx t7po WPout s.b. WPOut * fix handling of cancel in main dialog ]]-- Recipe = "Microidealize" Version = "4.1.1" ReVersion = Recipe .. " " .. Version kOriginalStructureOrNewBest = 1 -- the starting structure, or any subsequent improvement, will be stored in this quicksave slot best_score = 0 orig_score = 0 min_idealize_length = 1 max_idealize_length = 3 min_residue = 1 max_residue = 999 worst_first = true original_slow_filters_setting = 0 kDefaultWiggle = 3 WF = 1 WigglePower = "" WPOut = "" PowerNames = { l = "low", m = "medium", h = "high", a = "auto", } WFDefaults = { l = 2, m = 4, h = 4, a = 3, } WPPrompt = "" HighPowerOK = false kSphereRadius = 10 segCnt = 0 segCnt2 = 0 dolocked = false -- if locked sections present, work on locked sections only locksphr = false -- if locked sections present, include locked sections in wiggle sphere ulcksphr = true -- if locked sections present, include unlocked sections in wiggle sphere lockedL = {} -- list of locked segments lockedS = {} -- set of locked segments unlockedS = {} -- set of unlocked segments idealz = {} -- table of ideality by segment HASFILTER = false -- puzzle has filters FILTEROFF = false -- disable filters if true VERBOSE = false -- massive debug if true TRACKED = false -- tracked ideality changes by segment function r3 ( i ) return i - i % 0.001 end function FX ( tag, funcX, ... ) if VERBOSE then print ( tag, unpack ( arg ) ) end local ret = funcX ( unpack ( arg ) ) return ret end function pv ( ... ) if VERBOSE then print ( ... ) end end SLT = { -- SLT--SLT--SLT--SLT--SLT--SLT--SLT--SLT--SLT--SLT-- --[[ SLT - Segment set, list, and type module v0.5 Includes the segment set and list module and the segment type module developed by Timo van der Laan. The following Foldit recipes contain the original code for these modules: * Tvdl enhanced DRW 3.1.1 - https://fold.it/portal/recipe/102840 * TvdL DRemixW 3.1.2 - https://fold.it/portal/recipe/102398 The "set and list" module performs logical operations and transformations on tables containing ranges of segment. The segment type module find lists and sets of segments with various properties, such as selected or frozen. A "list" is one-dimensional table containing segment numbers. A "set" is a two-dimensional table containing segment number ranges. For example, given a list of segments: list = { 1, 2, 3, 7, 8, 11, 13, 14, 15 } the corresponding set is: set = { { 1, 3 }, { 7, 8 }, { 11, 11 }, {13, 15 } } Most functions assume that the sets are well-formed, meaning they are ordered and have no overlaps. As an example, the method FindUnlocked returns a set of all the unlocked segments in a puzzle. The method can be called as follows: funlocked = SLT:FindUnlocked () The return value funlocked is a two-dimensional table containing ranges of unlocked segments. In source format, the table might look like this: funlocked = { { 27, 35, }, { 47, 62, }, { 78, 89, }, } The code to use this table would look like: -- -- for each range of segments -- for ii = 1, #funlocked do -- -- for each segment in the range, so something -- for jj = funlocked [ ii ] [ 1 ], funlocked [ ii ] [ 2 ] do ... something ... end end This psuedo-module is a table containing a mix of data fields and methods. This wiki article explains the packaging technique: https://foldit.fandom.com/wiki/Lua_packaging_for_Foldit Authorship ---------- Original by Timo van der Laan: 02-05-2012 TvdL Free to use for non commercial purposes French comments by Bruno Kestemont and perhaps others. v0.1 - LociOiling + extract and reformat code v0.2 - LociOiling - 2017/11/03 + add primary FindUnlocked function v0.3 - LociOiling + add FindRotamers function v0.4 - LociOiling - 2019/10/29 + package as table + remove dependencies on segCnt and segCnt2 v0.5 - LociOiling - 2019/12/17 + convert functions to methods, update internal references ]]-- -- -- variables -- segCnt = nil, -- segment count, not adjusted for ligands segCnt2 = nil, -- segment count, not including terminal ligands -- -- initializer - can be called externally, but invoked inline if segCnt or segCnt2 are nil -- Init = function ( self ) self.segCnt = structure.GetCount () self.segCnt2 = self.segCnt while structure.GetSecondaryStructure ( self.segCnt2 ) == "M" do self.segCnt2 = self.segCnt2 - 1 end end, -- -- segment set and list functions -- SegmentListToSet = function ( self, list ) -- retirer doublons local result = {} local ff = 0 local ll = -1 table.sort ( list ) for ii = 1, #list do if list [ ii ] ~= ll + 1 and list [ ii ] ~= ll then -- note: duplicates are removed if ll > 0 then result [ #result + 1 ] = { ff, ll } end ff = list [ ii ] end ll = list [ ii ] end if ll > 0 then result [ #result + 1 ] = { ff, ll } end return result end, SegmentSetToList = function ( self, set ) -- faire une liste a partir d'une zone local result = {} for ii = 1, #set do for kk = set [ ii ] [ 1 ], set [ ii ] [ 2 ] do result [ #result + 1 ] = kk end end return result end, SegmentCleanSet = function ( self, set ) -- Makes it well formed return self:SegmentListToSet ( self:SegmentSetToList ( set ) ) end, SegmentInvertSet = function ( self, set, maxseg ) -- -- Gives back all segments not in the set -- maxseg is added for ligand -- local result={} if maxseg == nil then maxseg = structure.GetCount () end if #set == 0 then return { { 1, maxseg } } end if set [ 1 ] [ 1 ] ~= 1 then result [ 1 ] = { 1, set [ 1 ] [ 1 ] - 1 } end for ii = 2, #set do result [ #result + 1 ] = { set [ ii - 1 ] [ 2 ] + 1, set [ ii ] [ 1 ] - 1, } end if set [ #set ] [ 2 ] ~= maxseg then result [ #result + 1 ] = { set [ #set ] [ 2 ] + 1, maxseg } end return result end, SegmentInvertList = function ( self, list ) if self.segCnt2 == nil then self:Init () end table.sort ( list ) local result = {} for ii = 1, #list - 1 do for jj = list [ ii ] + 1, list [ ii + 1 ] - 1 do result [ #result + 1 ] = jj end end for jj = list [ #list ] + 1, self.segCnt2 do result [ #result + 1 ] = jj end return result end, SegmentInList = function ( self, seg, list ) -- verifier si segment est dans la liste table.sort ( list ) for ii = 1, #list do if list [ ii ] == seg then return true elseif list [ ii ] > seg then return false end end return false end, SegmentInSet = function ( self, set, seg ) --verifie si segment est dans la zone for ii = 1, #set do if seg >= set [ ii ] [ 1 ] and seg <= set [ ii ] [ 2 ] then return true elseif seg < set [ ii ] [ 1 ] then return false end end return false end, SegmentJoinList = function ( self, list1, list2 ) -- fusionner 2 listes de segments local result = list1 if result == nil then return list2 end for ii = 1, #list2 do result [ #result + 1 ] = list2 [ ii ] end table.sort ( result ) return result end, SegmentJoinSet = function ( self, set1, set2 ) --fusionner (ajouter) 2 zones return self:SegmentListToSet ( self:SegmentJoinList ( self:SegmentSetToList ( set1 ), self:SegmentSetToList ( set2 ) ) ) end, SegmentCommList = function ( self, list1, list2 ) -- chercher intersection de 2 listes local result = {} table.sort ( list1 ) table.sort ( list2 ) if #list2 == 0 then return result end local jj = 1 for ii = 1, #list1 do while list2 [ jj ] < list1 [ ii ] do jj = jj + 1 if jj > #list2 then return result end end if list1 [ ii ] == list2 [ jj ] then result [ #result + 1 ] = list1 [ ii ] end end return result end, SegmentCommSet = function ( self, set1, set2 ) -- intersection de 2 zones return self:SegmentListToSet ( self:SegmentCommList ( self:SegmentSetToList ( set1 ), self:SegmentSetToList ( set2 ) ) ) end, SegmentSetMinus = function ( self, set1, set2 ) return self:SegmentCommSet ( set1, self:SegmentInvertSet ( set2 ) ) end, SegmentPrintSet = function ( self, set ) print ( self:SegmentSetToString ( set ) ) end, SegmentSetToString = function ( self, set ) -- pour pouvoir imprimer local line = "" for ii = 1, #set do if ii ~= 1 then line = line .. ", " end line = line .. set [ ii ] [ 1 ] .. "-" .. set [ ii ] [ 2 ] end return line end, SegmentSetInSet = function ( self, set, sub ) if sub == nil then return true end -- -- Checks if sub is a proper subset of set -- for ii = 1, #sub do if not self:SegmentRangeInSet ( set, sub [ ii ] ) then return false end end return true end, SegmentRangeInSet = function ( self, set, range ) -- verifier si zone est dans suite if range == nil or #range == 0 then return true end local bb = range [ 1 ] local ee = range [ 2 ] for ii = 1, #set do if bb >= set [ ii ] [ 1 ] and bb <= set [ ii ] [ 2 ] then return ( ee <= set [ ii ] [ 2 ] ) elseif ee <= set [ ii ] [ 1 ] then return false end end return false end, SegmentSetToBool = function ( self, set ) --vrai ou faux pour chaque segment utilisable ou non local result = {} for ii = 1, structure.GetCount () do result [ ii ] = self:SegmentInSet ( set, ii ) end return result end, -- -- End of Segment Set module -- -- -- Module Find Segment Types -- FindMutablesList = function ( self ) if self.segCnt2 == nil then self:Init () end local result = {} for ii = 1, self.segCnt2 do if structure.IsMutable ( ii ) then result [ #result + 1 ] = ii end end return result end, FindMutables = function ( self ) return self:SegmentListToSet ( self:FindMutablesList () ) end, FindFrozenList = function ( self ) if self.segCnt2 == nil then self:Init () end local result = {} for ii = 1, self.segCnt2 do if freeze.IsFrozen ( ii ) then result [ #result + 1 ] = ii end end return result end, FindFrozen = function ( self ) return self:SegmentListToSet ( self:FindFrozenList () ) end, FindLockedList = function ( self ) if self.segCnt2 == nil then self:Init () end local result = {} for ii = 1, self.segCnt2 do if structure.IsLocked ( ii ) then result [ #result + 1 ] = ii end end return result end, FindLocked = function ( self ) return self:SegmentListToSet ( self:FindLockedList () ) end, FindUnlockedList = function ( self ) if self.segCnt2 == nil then self:Init () end local result = {} for ii = 1, self.segCnt2 do if not structure.IsLocked ( ii ) then result [ #result + 1 ] = ii end end return result end, FindUnlocked = function ( self ) return self:SegmentListToSet ( self:FindUnlockedList () ) end, FindZeroScoreList = function ( self ) if self.segCnt == nil then self:Init () end local result = {} for ii = 1, self.segCnt do local sub = 0 for jj = 1, #SubScores do sub = sub + current.GetSegmentEnergySubscore ( ii, SubScores [ jj ] [ 1 ] ) end if sub == 0 then result [ #result + 1 ] = ii end end return result end, FindZeroScore = function ( self ) return self:SegmentListToSet ( self:FindZeroScoreList () ) end, FindRotamersList = function ( self ) if self.segCnt == nil then self:Init () end local result = {} for ii = 1, self.segCnt do local rots = rotamer.GetCount ( ii ) if rots > 1 then result [ #result + 1 ] = ii end end return result end, FindRotamers = function ( self ) return self:SegmentListToSet ( self:FindRotamersList () ) end, FindSelectedList = function ( self ) if self.segCnt == nil then self:Init () end local result = {} for ii = 1, self.segCnt do if selection.IsSelected ( ii ) then result [ #result + 1 ] = ii end end return result end, FindSelected = function ( self ) return self:SegmentListToSet ( self:FindSelectedList () ) end, FindAAtypeList = function ( self, aa ) if self.segCnt2 == nil then self:Init () end local result = {} for ii = 1, self.segCnt2 do if structure.GetSecondaryStructure ( ii ) == aa then result [ #result + 1 ] = ii end end return result end, FindAAtype = function ( self, aa ) return self:SegmentListToSet ( self:FindAAtypeList ( aa ) ) end, FindAminotype = function ( self, at ) --NOTE: only this one gives a list not a set if self.segCnt2 == nil then self:Init () end local result={} for ii = 1, self.segCnt2 do if structure.GetAminoAcid ( ii ) == at then result [ #result + 1 ] = ii end end return result end, }-- SLT--SLT--SLT--SLT--SLT--SLT--SLT--SLT--SLT--SLT-- -- Thanks too Rav4pl function ShuffleTable(tab) --randomize order of elements local cnt=#tab for i=1,cnt do local r=math.random(cnt) tab[i],tab[r]=tab[r],tab[i] end return tab end function GetScore () pv ( "GetScore: enter" ) if not FILTEROFF then score = current.GetEnergyScore () else behavior.SetFiltersDisabled ( false ) score = current.GetEnergyScore () behavior.SetFiltersDisabled ( true ) end pv ( "GetScore: end, score = " .. score ) return score end function DoesPuzzleHaveFilters () local names = filter.GetNames () if names ~= nil and #names > 0 then return true else return false end end function SphereSelect ( start_idx, end_idx ) selection.DeselectAll () for ii = 1, segCnt2 do for jj = start_idx, end_idx do if lockedL [ ii ] then if locksphr then if structure.GetDistance ( ii , jj ) < kSphereRadius then selection.Select ( ii ) end end else if ulcksphr then if structure.GetDistance ( ii , jj ) < kSphereRadius then selection.Select ( ii ) end end end end end end -- -- GetWorklist -- -- return set of segments to work on -- -- sSet - segment set -- lenX - length -- gMinR - minimum residue -- gMaxR - maximum residue -- function GetWorklist ( sSet, lenX, gMinR, gMaxR ) local lsx = {} for uu = 1, #sSet do local minR = sSet [ uu ] [ 1 ] local maxR = sSet [ uu ] [ 2 ] if ( #sSet == 1 and minR >= gMinR and maxR <= gMaxR ) or ( #sSet > 1 and minR > gMinR and maxR <= gMaxR ) then for ii = minR, maxR - lenX + 1 do lsx [ #lsx + 1 ] = { seg1 = ii, seg2 = ii + lenX - 1, ideal = nil, after = nil, } end end end return lsx end function GoSegment ( start_idx, end_idx, startideal ) pv ( "GoSegment: " .. start_idx .. "-" .. end_idx ) if start_idx > 1 then FX ( "structure.InsertCut", structure.InsertCut, start_idx ) end if end_idx < segCnt2 then FX ( "structure.InsertCut", structure.InsertCut, end_idx ) end FX ( "selection.DeselectAll", selection.DeselectAll ) FX ( "selection.SelectRange ", selection.SelectRange, start_idx , end_idx ) FX ( "structure.IdealizeSelected", structure.IdealizeSelected ) if start_idx > 1 then FX ( "structure.DeleteCut", structure.DeleteCut, start_idx ) end if end_idx < segCnt2 then FX ( "structure.DeleteCut", structure.DeleteCut, end_idx ) end SphereSelect ( start_idx, end_idx ) pv ( "GoSegment: before wiggle" ) FX ( "structure.WiggleSelected", structure.WiggleSelected, kDefaultWiggle * WF ) pv ( "GoSegment: after wiggle" ) pv ( "GoSegment: before GetScore" ) local score = GetScore () pv ( "GoSegment: after GetScore" ) if score > best_score then local newideal = ScoreIdealitySection ( start_idx, end_idx ) best_score = score print ( "Improvement to ".. r3 ( best_score ) .. ", ideality change " .. r3 ( newideal - startideal ) ) save.Quicksave ( kOriginalStructureOrNewBest ) end save.Quickload ( kOriginalStructureOrNewBest ) pv ( "GoSegment: end" ) end function ScoreIdealitySection ( seg1, seg2 ) local ideal = 0 for ii = seg1, seg2 do ideal = ideal + current.GetSegmentEnergySubscore ( ii, "ideality" ) end return ideal end function ScoreIdeality ( wlist ) local tideal = 0 for ii = 1, #wlist do wlist [ ii ].ideal = ScoreIdealitySection ( wlist [ ii ].seg1, wlist [ ii ].seg2 ) tideal = tideal + wlist [ ii ].ideal end return wlist, tideal end function SortIdealAsc ( xyzzy ) table.sort ( xyzzy, function ( a, b ) return a.ideal < b.ideal end) return xyzzy end function Idealize ( idealize_length ) local start_score = GetScore () print ( "----------------------------------------" ) print ( "Idealizing length " .. idealize_length .. ", start score = " .. r3 ( start_score ) ) local inc local worklist = {} if dolocked then worklist = GetWorklist ( lockedS, idealize_length, min_residue, max_residue ) else worklist = GetWorklist ( unlockedS, idealize_length, min_residue, max_residue ) end local tideal = 0 worklist, tideal = ScoreIdeality ( worklist ) local meanideal = tideal / #worklist print ( "Mean ideality = " .. r3 ( meanideal ) .. " for " .. #worklist .. " sections" ) if worst_first then worklist = SortIdealAsc ( worklist ) else worklist = ShuffleTable ( worklist ) end for ii = 1, #worklist do print ( "Idealizing " .. worklist [ ii ].seg1 .. "-" .. worklist [ ii ].seg2 .. " (" .. ii .. "/" .. #worklist .. "), ideality = " .. r3 ( worklist [ ii ].ideal ) ) GoSegment ( worklist [ ii ].seg1, worklist [ ii ].seg2, worklist [ ii ].ideal ) worklist [ ii ].after = ScoreIdealitySection ( worklist [ ii ].seg1, worklist [ ii ].seg2 ) end local stop_score = GetScore () local len_gain = stop_score - start_score print ( "End length " .. idealize_length .. ", score = " .. r3 ( stop_score ) .. ", gain = " .. r3 ( len_gain ) ) end function GetParameters () local changed = false local uerror = "" local rc repeat local dlog = dialog.CreateDialog ( ReVersion ) dlog.WigglePower = dialog.AddTextbox ( "Wiggle Power", WPOut ) dlog.WPkey = dialog.AddLabel ( WPPrompt ) dlog.WF = dialog.AddSlider ( "Wiggle Factor", WF, 1, 5, 0 ) dlog.min_idealize_length = dialog.AddSlider ( "Min idealize len" , min_idealize_length , 1 , 20 , 0 ) dlog.max_idealize_length = dialog.AddSlider ( "Max idealize len" , max_idealize_length , 1 , 20 , 0 ) dlog.min_residue = dialog.AddSlider ( "Min residue" , 1 , 1 , segCnt2 , 0 ) dlog.max_residue = dialog.AddSlider ( "Max residue" , segCnt2 , 1 , segCnt2 , 0 ) dlog.worst_first = dialog.AddCheckbox ( "Worst first?" , worst_first ) if #lockedS > 0 then dlog.dolocked = dialog.AddCheckbox ( "Do locked segments only?" , dolocked ) dlog.locksphr = dialog.AddCheckbox ( "Include locked in wiggle?" , locksphr ) dlog.ulcksphr = dialog.AddCheckbox ( "Include unlocked in wiggle?" , ulcksphr ) end dlog.FILTEROFF = dialog.AddCheckbox ( "Disable filters" , FILTEROFF ) dlog.VERBOSE = dialog.AddCheckbox ( "Verbose output" , VERBOSE ) dlog.TRACKED = dialog.AddCheckbox ( "Report ideality" , TRACKED ) dlog.ok = dialog.AddButton ( "OK" , 1 ) dlog.cancel = dialog.AddButton ( "Cancel" , -1 ) rc = dialog.Show ( dlog ) uerror = "" if rc > 0 then local WPtest = dlog.WigglePower.value:lower() WPtest = WPtest:sub ( 1, 1 ) local WPtnam = PowerNames [ WPtest ] if WPtnam ~= nil then if WPtest ~= "h" or HighPowerOK then print ( "new wiggle power = " .. WPtnam ) WPOut = WPtnam behavior.SetWigglePower ( WPtest ) else uerror = "high wiggle power not allowed on this puzzle" print ( "ERROR: " .. uerror ) end else uerror = "invalid wiggle power entered: \"" .. dlog.WigglePower.value .. "\"" print ( "ERROR: " .. uerror ) end WF = dlog.WF.value min_idealize_length = dlog.min_idealize_length.value max_idealize_length = dlog.max_idealize_length.value min_residue = dlog.min_residue.value max_residue = dlog.max_residue.value worst_first = dlog.worst_first.value if #lockedS > 0 then dolocked = dlog.dolocked.value locksphr = dlog.locksphr.value ulcksphr = dlog.ulcksphr.value end FILTEROFF = dlog.FILTEROFF.value VERBOSE = dlog.VERBOSE.value TRACKED = dlog.TRACKED.value end until rc < 0 or ( not changed and uerror:len () == 0 ) return rc > 0 end -- -- Ident - print identifying information at beginning and end of recipe -- -- slugline - first line to print - normally recipe name and version -- function Ident ( slugline ) local function round ( ii ) return ii - ii % 0.001 end print ( slugline ) print ( "Puzzle: " .. puzzle.GetName () .. " (" .. puzzle.GetPuzzleID () .. ")" ) print ( "Track: " .. ui.GetTrackName () ) gname = user.GetGroupName () if gname ~= nil then gname = " (" .. gname .. ")" else gname = "" end print ( "User: " .. user.GetPlayerName () .. gname ) local scoretype = scoreboard.GetScoreType () local scort = "" if scoretype == 0 then scort = "soloist" elseif scoretype == 1 then scort = "evolver" elseif scoretype == 2 then scort = "all hands" elseif scoretype == 3 then scort = "no score" else scort = "unknown/error" end print ( "Rank: " .. scoreboard.GetRank ( scoretype ) .. " (" .. scort .. ")" ) local sGroup = scoreboard.GetGroupScore () if sGroup ~= nil then print ( "Group rank / score: " .. scoreboard.GetGroupRank () .. " / " .. round ( 10 * ( 800 - sGroup ) ) ) end end -- -- seedRandom -- original by KarenCH -- -- looks for a seed > 10,000,000 and < 2 ^ 32 -- -- v2 - LociOiling - 20191103 -- * added 2 ^ 32 overflow check -- function seedRandom() local seed = os.time () / math.abs ( current.GetEnergyScore () ) seed = seed % 0.001 seed = 1 / seed while seed < 10000000 do seed = seed * 1000 end while seed > 2 ^ 32 do seed = seed / 10 end seed = seed - seed % 1 print ( "Random number seed = " .. seed ) math.randomseed( seed ) -- throw away a couple of randoms math.random () math.random () end function Initialize () seedRandom () segCnt = structure.GetCount() segCnt2 = segCnt while structure.GetSecondaryStructure ( segCnt2 ) == "M" do segCnt2 = segCnt2 - 1 end print ( "initial segment count: " .. segCnt ) if segCnt ~= segCnt2 then print ( "ligand found, adjusted segment count: " .. segCnt2 ) end for ii = 1, segCnt2 do lockedL [ #lockedL + 1 ] = structure.IsLocked ( ii ) end lockedS = SLT:FindLocked () print ( #lockedS .. " locked sections found" ) unlockedS = SLT:FindUnlocked () print ( #unlockedS .. " unlocked sections found" ) local names = filter.GetNames () if names ~= nil and #names > 0 then HASFILTER = true FILTEROFF = true end -- -- wiggle power/wiggle factor -- WigglePower = behavior.GetWigglePower () WPOut = PowerNames [ WigglePower ] WF = WFDefaults [ WigglePower ] HighPowerOK = behavior.HighPowerAllowed () if HighPowerOK then WPPrompt = "wiggle power: l = low, m = medium, h = high, a = auto" else WPPrompt = "wiggle power: l = low, m = medium, a = auto" end end function main () Ident ( ReVersion ) save.Quicksave ( kOriginalStructureOrNewBest ) best_score = GetScore () orig_score = best_score print ( "Start score " .. r3 ( best_score ) ) Initialize () original_slow_filters_setting = behavior.GetFiltersDisabled () if GetParameters () then if FILTEROFF then behavior.SetFiltersDisabled ( true ) end print ( "--" ) print ( "Options: " ) print ( "Wiggle power: " .. WPOut ) print ( "Wiggle factor: " .. WF ) print ( "Min idealize length: " .. min_idealize_length ) print ( "Max idealize length: " .. max_idealize_length ) if #lockedS > 0 then print ( "Idealize locked: " .. tostring ( dolocked ) ) print ( "Include locked in sphere: " .. tostring ( locksphr ) ) print ( "Include unlocked in sphere: " .. tostring ( ulcksphr ) ) end print ( "Worst first: " .. tostring ( worst_first ) ) print ( "Disable filters: " .. tostring ( FILTEROFF ) ) print ( "Verbose output: " .. tostring ( VERBOSE ) ) print ( "Track ideality: " .. tostring ( TRACKED ) ) -- -- record locked status and initial ideality of each segment -- if TRACKED then for ii = 1, segCnt2 do local ideal = current.GetSegmentEnergySubscore ( ii, "ideality" ) idealz [ #idealz + 1 ] = { seg = ii, locked = lockedL [ ii ], ideal = ideal, after = 0, } end end local inc = 1 if min_idealize_length > max_idealize_length then inc = -1 end for len = min_idealize_length, max_idealize_length, inc do Idealize ( len ) end end cleanup () end function cleanup ( errmsg ) if CLEANUPENTRY ~= nil then return end CLEANUPENTRY = true 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 recipe name, puzzle, track, time, score, and gain -- Ident ( ReVersion .. " " .. reason ) if reason == "error" then print ( "Unexpected error detected" ) print ( "Error line: " .. line ) print ( "Error: \"" .. errmsg .. "\"" ) end -- -- reset clash importance, clear selections, restore structures, etc. -- save.Quickload ( kOriginalStructureOrNewBest ) local final_score = GetScore () local gain = final_score - orig_score print ( "start score = " .. r3 ( orig_score ) ) print ( "end score = " .. r3 ( final_score ) ) print ( "gain = " .. r3 ( gain ) ) behavior.SetClashImportance ( 1.0 ) behavior.SetFiltersDisabled ( original_slow_filters_setting ) if TRACKED and idealz ~= nil and #idealz > 0 then -- -- record final ideality -- for ii = 1, segCnt2 do idealz [ ii ].after = current.GetSegmentEnergySubscore ( ii, "ideality" ) end print ( "--spreadsheet output--" ) print ( "segment\tlocked\tbefore\tafter\tdiff" ) for ii = 1, #idealz do local locked if idealz [ ii ].locked then locked = "L" else locked = "U" end local before = r3 ( idealz [ ii ].ideal ) local after = r3 ( idealz [ ii ].after ) local diff = r3 ( after - before ) print ( idealz [ ii ].seg .. "\t" .. locked .. "\t" .. before .. "\t" .. after .. "\t" .. diff ) end end if errmsg == nil then end end xpcall ( main, cleanup )

Comments


LociOiling Lv 1

Microidealize 4.1 can now process multiple lengths in one run.

The settings "min idealize length" and "max idealize length" let you adjust the lengths. The recipe always starts with min length. If min length is greater than max length, the recipe works its way down to max length, otherwise it works its way up.

There are also new settings for Wiggle Power and Wiggle Factor. Wiggle Power shows the current wiggle power setting and lets you adjust it. Wiggle Factor is similar to what's found in EDRW/DRemixW, and multiplies the number of wiggles. Wiggle Factor's initial setting is based on the current wiggle power.

As before, "min residue" and "max residue" allow you to idealize only part of the protein.

The "worst first" setting is from Microidealize 4.0 test, and idealizes the least ideal sections first if checked. Otherwise, sections are idealized in random order.

The "disable filters" setting replaces the "score type" setting in previous versions of the recipe. If the puzzle has filters, this option is checked by default, and filters are only enabled when the recipe checks the score.

The "verbose output" option, if checked, produces output detailing all calls in the central part of the idealize process.

The "report ideality" option, if checked, produces a table of ideality changes by segment. This table was produced by default in Microidealize 4.0 test. The table output can be copied from the scriptlog file and pasted into a spreadsheet.

There was some effort to provide additional score detail in the output, but this version still doesn't tell you how long things took.

There were several other minor changes to the code, such as updating the method used to determine whether there are filters to use the new filter.GetNames call. A couple of internal tables were updated to use named fields instead of offsets. The random number generator now gets seeded, which might be important if you select the random order option.

LociOiling Lv 1

Microidealize 4.1.1 fixes a couple of bugs:

  1. changing wiggle power could crash the recipe
  2. the cancel button in the dialog didn't stop the recipe

There are also some slight cosmetic fixes.