Icon representing a recipe

Recipe: Bravo Ligand Loader v1.0

created by bravosk8erboy

Profile


Name
Bravo Ligand Loader v1.0
ID
109241
Shared with
Public
Parent
None
Children
None
Created on
November 14, 2025 at 21:46 PM UTC
Updated on
December 16, 2025 at 04:30 AM UTC
Description

Best for


Code


-- it is recommended to set a keyboard shortcut key to run this recipe -- can be used while still in the Library Compound menu. -- Make sure to press Accept Compound on the Load Library Compound menu. -- upload the current ligand so the library results are aligned with the current ligands position. -- this recipe is designed to work with the Ligand Batch Operator recipe -- https://fold.it/recipes/109250 -- it uses the note on segment #1 as reference to which quick save slot is to be used next -- it won't work if a note already exist that doesn't follow the autosave format -- just erase the note on segment #1 to start over. -- use this recipe to quickly load multiple small molecule / ligands into quicksave slots 1 to 100. -- useful for other recipes that can test multiple ligands in a single run. -- Authur: Bravo + Co-Pilot (sorry about the hard to read code) -- Fills quicksave slots 1..100 sequentially across multiple runs, tracking progress in segment 1's note. local function Ligand_Loader() -- ========== helpers (kept local inside Ligand_Loader) ========== -- Extract "AutoSaveSlot=<n>" marker from an existing note string. local function get_last_slot_from_note(note) if type(note) ~= "string" then note = "" end local m = note:match("AutoSaveSlot=(%d+)") local n = tonumber(m or "") or 0 if n < 0 then n = 0 end if n > 100 then n = 100 end return n end -- Insert/replace our marker in the note, preserving other text. local function set_last_slot_in_note(note, last_slot) if type(note) ~= "string" then note = "" end local marker = "AutoSaveSlot=" .. tostring(last_slot) if note:match("AutoSaveSlot=%d+") then return (note:gsub("AutoSaveSlot=%d+", marker, 1)) else if #note > 0 then return note .. " | " .. marker else return marker end end end -- Find the next available quicksave slot after `last_slot`, skipping filled ones. local function find_next_empty_slot(last_slot) local slot = last_slot + 1 if slot <= 100 then return slot end return nil end local function is_blank_or_no_marker(note) if type(note) ~= "string" then return true end local only_ws = (note:match("^%s*$") ~= nil) local has_marker = (note:match("AutoSaveSlot=%d+") ~= nil) -- "Blank" includes no marker or empty/whitespace string. return only_ws or not has_marker end local function safe_quickload(slot) -- Wrap quickload to avoid recipe abort on missing slot. local ok, result = pcall(function() return save.Quickload(slot) end) return ok and (result ~= false) end local function safe_quicksave(slot) local ok = pcall(function() save.Quicksave(slot) end) return ok end -- Scrub segment 1 notes for quicksave slots [start_slot..end_slot], re-saving each slot. local function scrub_segment1_notes(start_slot, end_slot, restore_slot) local scrubbed = 0 local skipped = 0 for slot = start_slot, end_slot do -- Try to load this quicksave; if there's nothing there, skip. if safe_quickload(slot) then -- Clear the note on segment 1 and re-save to the same slot. structure.SetNote(1, "") if safe_quicksave(slot) then scrubbed = scrubbed + 1 print(string.format(" - Scrubbed segment 1 note and re-saved slot %d", slot)) else skipped = skipped + 1 print(string.format(" - Re-save failed for slot %d (skipped)", slot)) end else skipped = skipped + 1 -- Not printing every skip keeps the log tidy; uncomment if needed: -- print(string.format(" - No quicksave present at slot %d (skipped)", slot)) end end -- Restore you back to the pose you just saved in this run, if possible. if restore_slot and safe_quickload(restore_slot) then print(string.format(" Restored to slot %d after scrubbing.", restore_slot)) end print(string.format("Scrub complete: %d slots updated, %d skipped.", scrubbed, skipped)) end local function prompt_scrub_if_needed(should_prompt, restore_slot) if not should_prompt then return end local ask = dialog.CreateDialog("Erase Quicksaves?") ask.Info1 = dialog.AddLabel("Scrub Segment 1 Notes in Existing Quicksaves?") ask.Info2 = dialog.AddLabel("We detected a blank/no-marker note on segment 1.") ask.Info3 = dialog.AddLabel("delete AutoSaveSlot=<n> from " ) ask.Info4 = dialog.AddLabel("existing quicksaves 2..100 ?") ask.Info5 = dialog.AddLabel("This is useful to standardize your quicksaves") ask.Info6 = dialog.AddLabel("and prepare for batch recipes.") ask.Info7 = dialog.AddLabel("Warning: This action modifies existing quicksaves.") ask.DoScrub = dialog.AddCheckbox("Scrub slots 2..100 now?", false) ask.OK = dialog.AddButton("OK", 1) ask.Cancel = dialog.AddButton("Cancel", 0) local clicked = dialog.Show(ask) if clicked == 1 and ask.DoScrub.value == true then print("Starting scrub of segment 1 notes across quicksaves 2..100 ...") scrub_segment1_notes(2, 100, restore_slot) else print("Scrub skipped. Existing quicksaves remain unchanged.") end end -- ========== main recipe logic ========== local function main() -- Read the tracking note on segment 1 and determine next candidate slot. local current_note = structure.GetNote(1) or "" local last_slot = get_last_slot_from_note(current_note) if last_slot >= 100 then print("all save slots are full") return end local next_slot = find_next_empty_slot(last_slot) if not next_slot then print("all save slots are full") return end -- *** IMPORTANT: update the note BEFORE the quicksave *** -- This ensures the saved pose contains the correct slot number in its note. local updated_note = set_last_slot_in_note(current_note, next_slot) structure.SetNote(1, updated_note) -- Now quicksave to the selected slot. save.Quicksave(next_slot) print(string.format(" Saved to quicksave slot %d", next_slot)) print(" ") print(" Use this recipe to quickly load multiple Ligands into quick save slots.") print(" This is to prepare for recipes that process multiple ligands.") print(" ") print(" Make sure to press Accept Compound on the Load Library Compound menu. ") print(" Erase Note on segment 1 to restart the save slot number.") -- Run the prompt AFTER saving if segment 1 note was blank/no-marker originally. local should_prompt = is_blank_or_no_marker(current_note) prompt_scrub_if_needed(should_prompt, next_slot) end local function on_error(err) print("Recipe error: " .. tostring(err)) if debug and debug.traceback then print(debug.traceback(err, 2)) end end xpcall(main, on_error) end Ligand_Loader()

Comments


Bruno Kestemont Lv 1

How to (this is a manual session that should ask you about 20 minutes).
Delete note from seg 1.
Load library.
Click on one of the compounts proposed, accept it.
Load the recipe. (click to erase all slots).
Load another compound.
Accept it.
Load the recipe.
Etc.

Keep note from seg 1 open. It should shange value each time you run the recipe.

THEN when you are finished, you'll see in your local saves that each loaded compound was saved locally. This will then be retrieved by another recipe, like bravo Ligand Batch Operator recipe, whose purpose is to load these compounds one by one and making some minimum actions. After one night, the best one should appear.

Bruno Kestemont Lv 1

Suggestion: add somethin else in the quicksave in order to be able to discriminate saves from separate cliens/libraries.
Suggesting adding the name of the client.