API Reference
Pourfecto.cobra_settingsPourfecto.configurationsPourfecto.labwaresPourfecto.objectivesPourfecto.ActuatorPourfecto.ChannelPourfecto.ConfigurationPourfecto.ConstrainedPositionPourfecto.ContinuousActuatorPourfecto.DeckPourfecto.DeckPositionPourfecto.DiscreteActuatorPourfecto.EmptyPositionPourfecto.HeadPourfecto.InstrumentPourfecto.InstrumentSettingsPourfecto.MaskPourfecto.MultiRepeaterPourfecto.ParameterDictPourfecto.PistonPourfecto.PourcastPourfecto.PriorityDictPourfecto.RepeaterStylePourfecto.SingleRepeaterPourfecto.UnconstrainedPositionPourfecto.add_stock!Pourfecto.add_stock!Pourfecto.compilePourfecto.concentrationPourfecto.config_to_jsonPourfecto.config_to_jsonPourfecto.configsPourfecto.df_to_labwarePourfecto.df_to_labwarePourfecto.df_to_stockPourfecto.df_to_stockPourfecto.flowsPourfecto.flows_by_configPourfecto.generatePourfecto.generatePourfecto.json_to_configPourfecto.json_to_configPourfecto.json_to_pourcastPourfecto.labware_indicesPourfecto.labware_to_dfPourfecto.labware_to_dfPourfecto.labware_to_dfPourfecto.model_solutionPourfecto.paramsPourfecto.planned_stocksPourfecto.plot_flowPourfecto.plot_flowsPourfecto.plot_slottingPourfecto.pourcast_to_jsonPourfecto.pourfectoPourfecto.pourfectoPourfecto.pourfectoPourfecto.pourfectoPourfecto.pourfectoPourfecto.quantityPourfecto.random_adverb_verb_pairsPourfecto.reagent_to_stringPourfecto.sanitize_tokensPourfecto.scheduling_objective_valuePourfecto.slacksPourfecto.slacksPourfecto.slotting_requirementsPourfecto.slottingdict_to_dfPourfecto.source_labwarePourfecto.source_stocksPourfecto.stock_to_dfPourfecto.stock_to_dfPourfecto.string_to_reagentPourfecto.target_labwarePourfecto.target_stocksPourfecto.transfer_indicesPourfecto.transfersPourfecto.transfers_by_configPourfecto.write_instrument_files
Full docstrings
Pourfecto.Actuator — Type
abstract type Actuator end
Represents the mechnaism used to move liquid in a Piston.
Pourfecto.Channel — Type
struct Channel capacity::Unitful.Volume end
A Channel defines the liquid handler's capacity for carrying liquid. This can be set independent of the piston.
Pourfecto.Configuration — Type
struct Configuration{I<:Instrument}
head::Head{I}
deck::Deck
settings::InstrumentSettings
endAn instance of a liquid handler instrument with definitions for the head, deck, and other settings
See Also: Head, Deck, InstrumentSettings
Pourfecto.ConstrainedPosition — Type
struct ConstrainedPosition <: DeckPosition name::String labware::Set{Type{<:Labware}} slots::Tuple{Int,Int} aspirate::Bool dispense::Bool plotting_shape::String end
Represents a position that can hold a set of specified JLIMS.Labware` Types. Constrained positions have specified slots for allowable labware
Pourfecto.ContinuousActuator — Type
abstract type ContinuousActuator <: Actuator end
Represents a continuous flow mechanism for liquid handler Piston types
See Also: Actuator
Pourfecto.Deck — Type
Deck = AbstractArray{<:DeckPosition}
Alias for an array of DeckPosition objects
Pourfecto.DeckPosition — Type
abstract type DeckPosition end
Supertype for deck position definitons
Pourfecto.DiscreteActuator — Type
abstract type DiscreteActuator <: Actuator end
a discrete shot mechanism for liquid handler Piston types
See Also: Actuator
Pourfecto.EmptyPosition — Type
struct EmptyPosition <: DeckPosition name::String end
Represents an empty or inaccessible position on the deck.
Pourfecto.Head — Type
struct Head{I<:Instrument} pistons::AbstractArray{<:Piston} channels::AbstractArray{Channel} mask::BitMatrix end
An instance of a head for a instrument I. Heads contains pistons that indpendently control aspiration and dispensation volumes and channels that access wells. Pistons and channels are usually arranged as an array. The head definition also includes a mask that defines which pistons are connected to which channels.
julia> abstract type ExSingleChannel <: Instrument end
julia> piston = Piston{ContinuousActuator,SingleRepeater}((20u"µL",200u"µL"),(20u"µL",200u"µL"),1)
julia> head = Head{ExSingleChannel}(
[piston],
[Channel(220u"µL")],
trues(1,1)
)Pourfecto.Instrument — Type
abstract type Instrument end
Abstract Supertype to define new instruments. Each new class of instrument should define a new abstract type
For example,
julia> abstract type NewInstrument <: Instrument end We refer to instances of liquid handlers as a Configuration which are parameterized by the abstract instrument type
julia> Configuration{SingleChannel} See Also Configuration
Pourfecto.InstrumentSettings — Type
InstrumentSettings = Dict{String,Any}
Alias for a Dict with settings for a particular instrument
Pourfecto.Mask — Type
struct Mask
head::Head
labware::Labware
asp::Function
disp::Function
asp_positions::Tuple{Integer,Integer}
disp_positions::Tuple{Integer,Integer}
endContains all of the mask related objects used to compute flows. We include separate entries for the aspirate and dispnese mask functions becuase they may be different for some liquid handlers.
Pourfecto.MultiRepeater — Type
abstract type MultiRepeater <: RepeaterStyle end
MultiRepeater styles allow the piston to dispense a single aspiration in multiple shots
See Also: RepeaterStyle
Pourfecto.ParameterDict — Type
ParameterDict = Dict{Symbol,Any}An Alias for Dict{Symbol,Any} that can be used to store keyword arguments for Pourfecto
Pourfecto.Piston — Type
struct Piston{A <: Actuator, R<: RepeaterStyle} minAsp::Unitful.Volume maxAsp::Unitful.Volume minDisp::Unitful.Volume maxDisp::Unitful.Volume deadPad::Real end
Pistons control how liquid moves in and out of the Head of a Liquid handler. They are parameterized by an Actuator and a [RepeaterSytle]. The fields of the piston define their maximum and minimum aspirating and dispensing volumes. The deadPad field is a multiplicative factor to account for error and miscalibration in the piston.
Pourfecto.Pourcast — Type
PourcastA result container for the pourfecto workflow. Pourcast bundles the relevant source/target stocks and labware, the instrument configuration set used for scheduling, the parameters supplied to pourfecto, and the resulting model solution and objective value.
Pourfecto.PriorityDict — Type
PriorityDict = Dict{String,UInt64}Dictionary type alias mapping reagent identifiers to a priority rank used during the Pourfecto planning stage.
Lower values represent higher priority (e.g., 1 is higher priority than 2). A common convention is to use typemax(UInt64) to indicate “lowest priority” or “effectively no priority preference”.
Examples
```jldoctest julia> PriorityDict( "sodium" => 1, "potassium" => 1, "ethanol" => 2, "water" => typemax(UInt64), ) Dict{String, UInt64} with 4 entries: "water" => 18446744073709551615 "ethanol" => 2 "sodium" => 1 "potassium" => 1
Pourfecto.RepeaterStyle — Type
abstract type RepeaterStyle end
Represents how a liquid handler handles repeated aspirations and dispenses. For example, a single channel pipette must dispense its entire aspirate in one shot, while other liquid handlers can fire repeated shots.
Pourfecto.SingleRepeater — Type
abstract type SingleRepeater <: RepeaterStyle end
SingleRepeater styles require that when a piston dispenses, it dispenses all of its volume in a single shot
See Also: RepeaterStyle
Pourfecto.UnconstrainedPosition — Type
struct UnconstrainedPosition <: DeckPosition name::String end
Represents a position that can hold any number of any labware
Pourfecto.cobra_settings — Constant
cobra_settingsA dictionary with settings for the cobra
dictionary keys:
pause=true: pause over each well before dispensing. If false, the instrument moves continuously while dispensing.predispenses=0: force the instrument to predispense a shot of liquid before starting the run.cobra_path: the local path the cobra should look for protocol files on the machine running the instrumentwashtime: set how long the wash system should flush the nozzles forAspPad = 1.125: Force the cobra to overaspirate by a factor of AspPad. Pourfecto takes this into account when planningAspDistnace = 1.5: set how many millimeters above the bottom of the labware the cobra should aspirate from.
Pourfecto.configurations — Constant
configurationsBy default, Pourfecto provides an assortment of pre-defined instruments. Use keys(configurations) to see available instruments
Pourfecto.labwares — Constant
labwaresBy default, Pourfecto provides an assortment of pre-defined labware. Use keys(labwares) to see available instruments
Pourfecto.objectives — Constant
objectivesPourfecto provides an assortment of pre-defined objectives. Use keys(objectives) to see available options
Note that many non-defualt options turn the problem into an MILP in the scheudling phase, which can lead to long and unpredictable run times.
Pourfecto.add_stock! — Method
add_stock!(lw::JLIMS.Labware, stock::JLIMS.Stock, row::Integer, col::Integer) -> JLIMS.LabwareDeposit stock into the well at (row, col) in lw.
This is a convenience wrapper around JLIMS.deposit! for manually filling labware. If the selected well is not empty, a warning is emitted and the function still attempts to deposit the stock.
Arguments
lw::JLIMS.Labware: Labware object to modify.stock::JLIMS.Stock: Stock to deposit.row::Integer: Row index of the target well.col::Integer: Column index of the target well.
Returns
JLIMS.Labware: The modified labware objectlw.
Pourfecto.compile — Method
compile(
directory::AbstractString,
pourcast::Pourcast;
packing_method::Function = packing_greedy,
kwargs...
) -> NothingCompile a Pourcast into one or more protocol folders on disk.
For each configuration in configs(pourcast), this function determines which source/target labware pairs must be simultaneously accessible (“slotted”) and uses packing_method to produce one or more feasible slotting layouts. For each layout, it extracts the corresponding well-to-well transfer submatrix for that configuration and writes instrument files into a protocol-specific subfolder.
Output layout
For each configuration c, files are written under:
directory/<config_type>/<protocol_name>/...
where <config_type> = string(get_config_type(configs(pourcast)[c])) and <protocol_name> is generated by random_adverb_verb_pairs.
Arguments
directory::AbstractString: Root directory where configuration/protocol subdirectories will be created.pourcast::Pourcast: The plan to compile (provides labware, configurations, and flows).
Keyword Arguments
packing_method::Function = packing_greedy: Packing/slotting routine called aspacking_method(slotting_pairs, config). It must return a collection of slotting dictionaries (one per generated protocol).check_quality::Bool = true: Force the compiler to check the quality of solution before compiling using thesolution_qualityfunction.kwargs...: Forwarded keyword arguments passed toslotting_requirements(...)andwrite_instrument_files(...)(e.g., a transfer threshold).
Side Effects
- Creates directories using
mkdirwhen needed. - Writes instrument/protocol files via
write_instrument_files.
Algorithm (per configuration)
- Compute
slotting_reqs = slotting_requirements(pourcast; kwargs...). - Convert
slotting_reqs[c]into a vector of(source::Labware, target::Labware)pairs that require co-slotting. - Generate one or more slotting solutions:
slotting_dicts = packing_method(slotting_pairs, configs(pourcast)[c]). - For each solution
p:- Determine slotted sources/targets from the dict keys.
- Convert labware to well-index selectors using
labware_indices(pourcast). - Slice the configuration transfer matrix:
protocol_design = transfers_by_config(pourcast)[c][s_idxs, t_idxs]. - Convert
protocol_designto aDataFrameand write files.
Pourfecto.concentration — Method
concentration(stock::JLIMS.Stock,ingredient::JLIMS.Ingredient)Return the concentration of an ingredient in a stock using the preferred units for that ingredient and stock
Pourfecto.config_to_json — Method
Lower a Configuration to a JSON string.
Pourfecto.configs — Method
configs(p::Pourcast) -> Vector{<:Configuration}Return the instrument configurations used by pourfecto to schedule the liquid handling operations
Pourfecto.df_to_labware — Method
df_to_labware(df::DataFrame, units::DataFrame; kwargs...) -> Vector{Labware}Reconstruct labware (and deposited well contents) from a dataframe representation.
df_to_labware expects labware metadata (labware, name, and well) plus the stock columns needed to reconstruct well contents. Stock content may be encoded in any stock dataframe format supported by df_to_stock ].
Required columns in df
df must include the following columns:
labware: Labware type code used byPourfecto.generate(labware_code, name). Valid codes arekeys(labwares).name: Name/identifier of the labware instance. Multiple rows may share the samename(andlabware) to indicate multiple wells on the same physical item.well: Well identifier in row/column form (e.g."A1","H2","B12")
All remaining columns are treated as stock data and are passed to df_to_stock.
Behavior
- Creates one labware instance per unique
(labware, name)pair. - Parses a
Stockper row from the stock columns usingdf_to_stock.
Arguments
df::DataFrame: Labware + stock data (one row per filled well).units::DataFrame: Units/metadata table for the stock columns (passed through todf_to_stock).
See also
Pourfecto.df_to_stock — Method
df_to_stock(df::DataFrame, units::DataFrame; kwargs...) -> Vector{Stock}Parse a pair of DataFrame representations into a vector of Stocks.
This is a format-dispatching wrapper that supports two encodings:
- "vc" (volume/concentration): tables include a
"volume"column (in bothdfandunits) and are parsed viavc_to_stock(df, units; kwargs...). - "q" (quantity): tables omit
"volume"and are parsed viaq_to_stock(df, units; kwargs...).
The function auto-detects the encoding by checking for the presence of the "volume" column in both df and units.
Arguments
df::DataFrame: Main stock table (one row per stock; columns depend on the chosen format).units::DataFrame: Units/metadata table aligned withdf(e.g., unit strings for numeric columns).
See also
Pourfecto.flows — Method
Pourfecto.flows_by_config — Method
flows_by_config(pc::Pourcast) -> Vector{Matrix{Float64}}Partition the full flow matrix into one flow matrix per configuration.
This function computes aspiration and dispense flow nodes across all configurations, then slices the global flow matrix flows(pc) into C matrices (one per configuration in configs(pc)). For configuration c, only entries corresponding to aspiration/dispense nodes whose configuration equals configs(pc)[c] are copied from the global flow matrix; all other entries remain zero.
Arguments
pc::Pourcast: A pour/transfer plan providing configurations, labware, and a global flow matrix viaflows(pc).
Returns
Vector{Matrix{Float64}}: A length-Cvectorflws_by_configwhereC == length(configs(pc)). Each entryflws_by_config[c]is anA×Dmatrix (A == length(asp_nodes),D == length(disp_nodes)) whose nonzero entries represent flows for configurationc.
Pourfecto.generate — Method
generate(T::AbstractString, name::AbstractString)Generate a labware instance from a registered labware code.
T is a short identifier (index code) used to look up a labware template in the global labwares registry. If the code is present, this method delegates to the underlying generator:
generate(labwares[T], name)
Examples
lw = generate("WP96", "plate_1") # code must exist in keys(labwares)Pourfecto.json_to_config — Method
Parse a JSON string back into a Configuration.
Pourfecto.json_to_pourcast — Method
json_to_pourcast(j::String) -> PourcastDeserialize a JSON string produced by pourcast_to_json back into a Pourcast instance.
Pourfecto.labware_indices — Method
labware_indices(pc::Pourcast) -> Tuple{Dict,Dict}Construct dictionaries mapping each source/target labware item to the vector of indices it occupies in the flattened transfer indexing scheme.
This function expands source_labware(pc) and target_labware(pc) into “by-index” vectors where each labware object is repeated length(x) times, then computes, for each labware object x, the positions (via findall) at which it appears in that expanded vector. The result is two dictionaries:
src_dict: maps eachsourcelabware object to a vector of integer indices into the expanded source index space.tgt_dict: maps eachtargetlabware object to a vector of integer indices into the expanded target index space.
These index vectors are intended to be used as selectors when indexing transfer data.
Arguments
pc::Pourcast: A pour/transfer plan providingsource_labware(pc)andtarget_labware(pc).
Returns
(src_dict, tgt_dict): A 2-tuple of dictionaries:src_dict::Dict{<:Any, <:AbstractVector{Int}}mapping each element ofsource_labware(pc)to a vector of indices.tgt_dict::Dict{<:Any, <:AbstractVector{Int}}mapping each element oftarget_labware(pc)to a vector of indices.
Pourfecto.labware_to_df — Function
labware_to_df(lw::Labware, format::AbstractString = "vc"; kwargs...) -> (DataFrame, DataFrame)Convenience method for exporting a single Labware object. Equivalent to labware_to_df([lw], format; kwargs...).
See also: labware_to_df(::Vector{<:Labware})
Pourfecto.labware_to_df — Function
labware_to_df(lws::Vector{<:Labware}, format::AbstractString = "vc"; kwargs...) -> (DataFrame, DataFrame)Convert labware into a dataframe representation suitable for serialization
The output contains one row per non-empty well and includes three labware descriptor columns plus the stock columns:
labware:string(typeof(lw))for the labware containing the wellname:JLIMS.name(lw)labware instance namewell:JLIMS.name(w)well identifier (e.g.,"A1")
Stock content is converted using stock_to_df in the requested format. The returned units dataframe corresponds to the stock columns (not the labware/name/well columns).
Arguments
lws::Vector{<:Labware}: Labware objects to export.format::AbstractString = "vc": Stock encoding passed tostock_to_df.
See also
Pourfecto.model_solution — Method
model_solution(p::Pourcast) -> Dict{Symbol,Any}Return the raw JuMP model output from the pourfecto algorithm.
Pourfecto.params — Method
params(p::Pourcast) -> ParameterDictReturn the parameter dictionary used to store all metadata from each pourfecto run.
Pourfecto.planned_stocks — Method
planned_stocks(p::Pourcast) -> Vector{Stock}Compute the planned target stocks from a Pourcast solution.
This function reconstructs each target stock as a mixture of the source stocks using the planned transfer volumes from the solution. Conceptually, for each target t:
planned[t] = Σₛ ( V[s,t] * source_stocks(p)[s] )
where V is the transfer-volume decision variable.
Details
- Transfer volumes are rounded to a number of digits derived from
params(p)[:min_vol_threshold]to reduce numerical noise:digits = -floor(log10(min_vol_threshold)). - Volumes are interpreted as microliters and converted to
Unitfulquantities viaV .* u"µL".
See Also
Pourfecto.plot_flow — Method
plot_flow(a::AspNode, d::DispNode, vol::Real; kwargs...) -> AnyCreate a visualization of a single flow from an aspiration node to a dispense node.
This helper plots the aspiration node a and dispense node d (via plot(a; kwargs...) and plot(d; kwargs...)) and combines them into a single figure with a title that includes the node configuration type and the requested volume (in µL).
Arguments
a::AspNode: Aspiration (source-side) flow node to visualize.d::DispNode: Dispense (target-side) flow node to visualize.vol::Real: Flow volume to display in the title (interpreted as µL).
Pourfecto.plot_flows — Method
plot_flows(pc::Pourcast; threshold::Real = 1e-4) -> VectorGenerate per-flow plots for all flows in a solved Pourcast above a threshold.
This function:
- Builds aspiration and dispense node grids with
compute_flow_nodesusing theconfigs(pc)and the corresponding source/target labware. - Reads the flow matrix via
flows(pc). - For each matrix entry
(i, j)whose flow is>= threshold, generates a plot withplot_flowand collects the results.
Arguments
pc::Pourcast: A solvedPourcast
See also
Pourfecto.plot_slotting — Method
plot_slotting(deck::Deck, slotting::SlottingDict;
wrapwidth::Integer=20,
titlefontsize::Integer=18,
fontsize::Integer=14,
plotsize=(1200,800)) -> Plots.PlotPlot a deck with labware arranged according to slotting.
Assumptions about slotting (based on your other plotting code):
slotting[lw][1]is aPositionobject on the deck (e.g.,ConstrainedPosition,StackPosition, ...).slotting[lw][2]is an index (row,col) within that position's slot grid where the labware is placed.
Assumptions about deck:
deckis either a matrix-like container (2D) of positions, or a vector of positions.
Pourfecto.pourcast_to_json — Method
pourcast_to_json(p::Pourcast) -> StringSerialize a Pourcast to a JSON string.
This converter prepares Pourcast contents for JSON encoding by first converting stocks, labware, and configurations into table-like or dictionary-like representations, then assembling a single dictionary and encoding it with JSON.json.
Pourfecto.pourfecto — Method
pourfecto(directory::AbstractString,
source_labware::Vector{<:JLIMS.Labware},
target_labware::Vector{<:JLIMS.Labware},
configs::Union{Vector{<:AbstractString},Vector{<:Configuration}};
kwargs...)Run the Pourfecto algorithm in planning and scheduling mode and automatically compile the resulting Pourcast(@ref) in directory.
If the Pourcast fails a solution_quality check, pourfecto will produce an error message while saving the Pourcast and quality report to the directory
Arguments
directory: The output directory (will be made if it doesn't already exist)source_labware: The JLIMS.Labware objects containing source stocks that pourfecto can use to create the targetstarget_labware: The JLIMS.Labware objects containing target stocks pourfecto is trying to create using the sourcesconfigs: The the Configuration objects or String identifiers for instrument configurations pourfecto can use to schedule the planned liquid transfers.
Keyword Arguments
objective = min_cost_flow: Set the scheduling objective for Pourfecto. Seekeys(objectives)for options.priority = Dict{String, UInt64}(): aPriorityDictthat specifies which reagents take precedence over others in a plan.quiet = true: Supress the printout of the solver.grb_timelimit = 30: Set the Gurobi solver'sTimeLimitparamter.grb_feasibility_tol = 1.0e-6: Set the Gurobi solver'sFeasibilityTolparameter.min_vol_threshold = 0.1: Set the minimum volume threshold in µL. Any transfer must be at least this large.require_nonzero = true: If a target contains a reagent, require that some amount of that reagent is delivered, even if the optimal solution is none.enforce_minimum_shot = false: Enforce the minimum shot volume constraints for each instrument. Caution turns the problem into an MILP.slack_tol = 0.01: Set the tolerance of the slacks in the solution to stay with in a percentage of the optimal value. A value of 0.01 equates to a 1% tolerance.config_costs = ones(length(configs)): Set the relative cost of using each configuration.solution_tolerance = 0.01: Set the limit for the magnitude of any single slack. A value of 1 indicates that the slack can be as large as the largest target in the model.
Pourfecto.pourfecto — Method
pourfecto(source_labware::Vector{<:JLIMS.Labware},
target_labware::Vector{<:JLIMS.Labware},
configs_string::Vector{<:AbstractString};kwargs...)Run the Pourfecto algorithm in planning and scheduling mode.
Arguments
source_labware: The JLIMS.Labware objects containing source stocks that pourfecto can use to create the targetstarget_labware: The JLIMS.Labware objects containing target stocks pourfecto is trying to create using the sourcesconfigs_string: The String identifiers for instrument configurations pourfecto can use to schedule the planned liquid transfers.
Keyword Arguments
objective = min_cost_flow: Set the scheduling objective for Pourfecto. Seekeys(objectives)for options.priority = Dict{String, UInt64}(): aPriorityDictthat specifies which reagents take precedence over others in a plan.quiet = true: Supress the printout of the solver.grb_timelimit = 30: Set the Gurobi solver'sTimeLimitparamter.grb_feasibility_tol = 1.0e-6: Set the Gurobi solver'sFeasibilityTolparameter.min_vol_threshold = 0.1: Set the minimum volume threshold in µL. Any transfer must be at least this large.require_nonzero = true: If a target contains a reagent, require that some amount of that reagent is delivered, even if the optimal solution is none.enforce_minimum_shot = false: Enforce the minimum shot volume constraints for each instrument. Caution turns the problem into an MILP.slack_tol = 0.01: Set the tolerance of the slacks in the solution to stay with in a percentage of the optimal value. A value of 0.01 equates to a 1% tolerance.config_costs = ones(length(configs)): Set the relative cost of using each configuration.solution_tolerance = 0.01: Set the limit for the magnitude of any single slack. A value of 1 indicates that the slack can be as large as the largest target in the model.
Pourfecto.pourfecto — Method
pourfecto(source_labware::Vector{<:JLIMS.Labware},
target_labware::Vector{<:JLIMS.Labware},
configs::Vector{<:Configuration};
kwargs...)Run the Pourfecto algorithm in planning and scheduling mode
Arguments
source_labware: The JLIMS.Labware objects containing source stocks that pourfecto can use to create the targetstarget_labware: The JLIMS.Labware objects containing target stocks pourfecto is trying to create using the sourcesconfigs: The instrument configurations pourfecto can use to schedule the planned liquid transfers.
Keyword Arguments
objective = min_cost_flow: Set the scheduling objective for Pourfecto. Seekeys(objectives)for options.priority = Dict{String, UInt64}(): aPriorityDictthat specifies which reagents take precedence over others in a plan.quiet = true: Supress the printout of the solver.grb_timelimit = 30: Set the Gurobi solver'sTimeLimitparamter.grb_feasibility_tol = 1.0e-6: Set the Gurobi solver'sFeasibilityTolparameter.min_vol_threshold = 0.1: Set the minimum volume threshold in µL. Any transfer must be at least this large.require_nonzero = true: If a target contains a reagent, require that some amount of that reagent is delivered, even if the optimal solution is none.enforce_minimum_shot = false: Enforce the minimum shot volume constraints for each instrument. Caution turns the problem into an MILP.slack_tol = 0.01: Set the tolerance of the slacks in the solution to stay with in a percentage of the optimal value. A value of 0.01 equates to a 1% tolerance.config_costs = ones(length(configs)): Set the relative cost of using each configuration.solution_tolerance = 0.01: Set the limit for the magnitude of any single slack. A value of 1 indicates that the slack can be as large as the largest target in the model.
Pourfecto.pourfecto — Method
pourfecto(source_labware::Vector{<:JLIMS.Labware},
target_labware::Vector{<:JLIMS.Labware};
kwargs...)Run the Pourfecto algorithm in planning mode using just the source and target labware
Arguments
source_labware: The JLIMS.Labware objects containing source stocks that pourfecto can use to create the targetstarget_labware: The JLIMS.Labware objects containing target stocks pourfecto is trying to create using the sources
Keyword Arguments
objective = min_cost_flow: Set the scheduling objective for Pourfecto. Seekeys(objectives)for options.priority = Dict{String, UInt64}(): aPriorityDictthat specifies which reagents take precedence over others in a plan.quiet = true: Supress the printout of the solver.grb_timelimit = 30: Set the Gurobi solver'sTimeLimitparamter.grb_feasibility_tol = 1.0e-6: Set the Gurobi solver'sFeasibilityTolparameter.min_vol_threshold = 0.1: Set the minimum volume threshold in µL. Any transfer must be at least this large.require_nonzero = true: If a target contains a reagent, require that some amount of that reagent is delivered, even if the optimal solution is none.enforce_minimum_shot = false: Enforce the minimum shot volume constraints for each instrument. Caution turns the problem into an MILP.slack_tol = 0.01: Set the tolerance of the slacks in the solution to stay with in a percentage of the optimal value. A value of 0.01 equates to a 1% tolerance.config_costs = ones(length(configs)): Set the relative cost of using each configuration.solution_tolerance = 0.01: Set the limit for the magnitude of any single slack. A value of 1 indicates that the slack can be as large as the largest target in the model.
Pourfecto.pourfecto — Method
pourfecto(sources::Vector{<:JLIMS.Stock},
targets::Vector{<:JLIMS.Stock};
kwargs...)Run the Pourfecto algorithm in planning mode using just the source and target stocks
Arguments
sources: The JLIMS.Stock objects that pourfecto can use to create the targetstargets: The JLIMS.Stock objects that pourfecto is trying to create using the sources
Keyword Arguments
objective = min_cost_flow: Set the scheduling objective for Pourfecto. Seekeys(objectives)for options.priority = Dict{String, UInt64}(): aPriorityDictthat specifies which reagents take precedence over others in a plan.quiet = true: Supress the printout of the solver.grb_timelimit = 30: Set the Gurobi solver'sTimeLimitparamter.grb_feasibility_tol = 1.0e-6: Set the Gurobi solver'sFeasibilityTolparameter.min_vol_threshold = 0.1: Set the minimum volume threshold in µL. Any transfer must be at least this large.require_nonzero = true: If a target contains a reagent, require that some amount of that reagent is delivered, even if the optimal solution is none.enforce_minimum_shot = false: Enforce the minimum shot volume constraints for each instrument. Caution turns the problem into an MILP.slack_tol = 0.01: Set the tolerance of the slacks in the solution to stay with in a percentage of the optimal value. A value of 0.01 equates to a 1% tolerance.config_costs = ones(length(configs)): Set the relative cost of using each configuration.solution_tolerance = 0.01: Set the limit for the magnitude of any single slack. A value of 1 indicates that the slack can be as large as the largest target in the model.
Pourfecto.quantity — Method
quantity(stock::JLIMS.Stock,ingredient::JLIMS.Ingredient)Return the quantity of an ingredient in a stock using the preferred units for that ingredient
Pourfecto.random_adverb_verb_pairs — Function
random_adverb_verb_pairs(adverbs, verbs, n; rng=Random.default_rng(), unique=true) -> Vector{String}Generate n directory-safe random strings of the form adverb_verb by sampling from adverbs and verbs (assumed to be Julia vectors of strings).
Directory-safety rules applied:
- lowercase
- spaces and hyphens become
_ - all other non
[a-z0-9_]characters removed - repeated
_collapsed; leading/trailing_stripped
If unique=true, results are unique; throws if n exceeds the number of possible unique combinations after sanitization.
Pourfecto.reagent_to_string — Method
reagent_to_string(chem::JLIMS.Chemical; chem_context::Vector{Module} = [JLIMS], kwargs...) -> StringConvert a JLIMS.Chemical into a stable string identifier.
This function attempts to return the registry key for chem when the chemical is registered in one of the modules listed in chem_context. This is useful because a registered chemical’s display name (JLIMS.name(chem)) is not necessarily the same string that chemparse expects to resolve it.
If chem is not found among the registered chemicals in chem_context, the function falls back to returning JLIMS.name(chem), which is sufficient to reconstruct “ad hoc” (unregistered) chemicals created on the fly.
See also: string_to_reagent
Pourfecto.sanitize_tokens — Method
sanitize_tokens(xs::AbstractVector{<:AbstractString};
lowercase::Bool=true,
replace_space_hyphen::Bool=true,
allow_digits::Bool=true,
keep_underscores::Bool=true,
drop_empty::Bool=true,
de_duplicate::Bool=true,
sort_items::Bool=false) -> Vector{String}Sanitize a vector of strings for directory-safe usage.
Rules (in order):
strip- (optional)
lowercase - (optional) replace whitespace and
-with_ - remove disallowed characters (keeps only
[a-z], optionally digits and_) - collapse consecutive
_ - trim leading/trailing
_ - (optional) drop empty strings
- (optional) de-duplicate (stable)
Examples
```julia adverbss = sanitizetokens(adverbs) verbss = sanitizetokens(verbs)
directory-safe pairings
names = randomadverbverbpairs(adverbss, verbs_s, 50)
Pourfecto.scheduling_objective_value — Method
scheduling_objective_value(p::Pourcast) -> RealReturn the objective value achieved by the schedule/plan.
Pourfecto.slacks — Method
slacks(p::Pourcast)Return the slack decision variable(s) from a Pourcast solution.
This is an accessor that extracts the solver/model variable stored under the key :slacks from the pourcast's model_solution
Pourfecto.slotting_requirements — Method
slotting_requirements(pc::Pourcast; threshold::Real = 1e-4) -> Vector{BitMatrix}Compute per-configuration source→target “slotting” requirements from a Pourcast plan by marking which source labware must be able to transfer to which target labware.
For each configuration c, this function returns a boolean matrix M = slotting_matrices[c] of size (S, T) where:
S == length(source_labware(pc))(number of source labware items)T == length(target_labware(pc))(number of target labware items)M[s, t] == trueif any transfer value associated with transfers fromsources[s]totargets[t]in configurationcexceedsthreshold. OtherwiseM[s, t] == false.
This is useful for determining which source/target pairs must be physically co-slotted/accessible in each configuration.
Keyword Arguments
threshold::Real = 1e-4: Minimum transfer magnitude considered “present”. Transfers> thresholdtrigger atruerequirement.
Returns
Vector{BitMatrix}: A length-Cvector of boolean matrices, one per configuration, whereC == length(configs(pc)). Each matrix has shape(S, T).
Notes
- The comparison is strictly greater than (
>)threshold. - Requires the following
Pourcast-related functions to be defined:transfers_by_config,configs,source_labware,target_labware,transfer_indices.
Examples
```julia reqs = slotting_requirements(pc)
Pourfecto.slottingdict_to_df — Method
slottingdict_to_df(slotting::SlottingDict) -> DataFrameConvert a SlottingDict describing labware placement into a DataFrame.
The input dictionary is expected to map each labware object s to a 2-tuple of the form (deck_position, slot), where:
deck_positionis an object whose human-readable identifier is given byname(deck_position).slotis aStringorIntegeridentifying the slot within that deck position.
Arguments
slotting::SlottingDict: Dictionary of labware placement info.
Returns
DataFrame: A table with columnsPosition,Slot,LabwareID, andName.
Pourfecto.source_labware — Method
source_labware(p::Pourcast) -> Vector{<:JLIMS.Labware}Return the source labware associated with p. The labware also provide the source stocks. They are stored separately because not all pourcasts have associated labware.
Pourfecto.source_stocks — Method
source_stocks(p::Pourcast) -> Vector{<:JLIMS.Stock}Return the source (input) stocks associated with p.
Pourfecto.stock_to_df — Function
stock_to_df(stocks::Vector{<:JLIMS.Stock}, format::AbstractString = "vc"; kwargs...) -> (DataFrame, DataFrame)Convert a vector of Stocks into a pair of dataframes (df, units) suitable for serialization.
Two formats are supported:
format = "vc": volume/concentration representation (stock_to_vc).format = "q": quantity representation (stock_to_q).
Arguments
stocks::Vector{<:JLIMS.Stock}: Stocks to convert.format::AbstractString = "vc": Output encoding; must be one of["vc", "q"].
See also
Pourfecto.string_to_reagent — Method
string_to_reagent(str::AbstractString, chem_type::Type{<:Chemical};
chem_context::Vector{Module} = [JLIMS], kwargs...) -> ChemicalConvert a string into a reagent (Chemical) instance.
The function first attempts to parse str using JLIMS.chemparse, which may return a registered reagent/chemical object from the provided chem_context. If parsing fails, it emits a warning and falls back to constructing a new chemical of type chem_type using str as the identifier/name and missing for unknown properties.
Arguments
str::AbstractString: The reagent identifier to parse (e.g., a registered name, alias, or other parseable representation).chem_type::Type{<:Chemical}: ConcreteChemicalsubtype to instantiate ifstris not registered / cannot be parsed.
Keyword Arguments
chem_context::Vector{Module} = [JLIMS]: Modules to search for registered chemicals during parsing (forwarded tochemparse).
Returns
- A
Chemicalobject. Ifchemparsesucceeds, the parsed/registered object is returned; otherwise, a newchem_type(str, missing, missing, missing)is returned.
Notes
This function is intentionally permissive: unknown reagents do not error, but are treated as chemicals with unspecified properties (missing), which may affect downstream calculations that require those properties.
See also: reagent_to_string
Pourfecto.target_labware — Method
target_labware(p::Pourcast) -> Vector{<:JLIMS.Labware}Return the target labware associated with p. The labware also provide the target stocks. They are stored separately because not all pourcasts have associated labware.
Pourfecto.target_stocks — Method
target_stocks(p::Pourcast) -> Vector{<:JLIMS.Stock}Return the target (output) stocks associated with p.
Pourfecto.transfer_indices — Method
transfer_indices(pc::Pourcast, source::Labware, target::Labware) -> Tuple{AbstractVector,AbstractVector}Return the transfer index selectors for a given source→target labware pair.
This function validates that source is present in source_labware(pc) and that target is present in target_labware(pc). If either is missing, it throws an ArgumentError. On success, it retrieves index selectors from labware_indices(pc) and returns the pair associated with the requested source and target.
Arguments
pc::Pourcast: A pour/transfer plan containing source/target labware lists and index mappings.source::Labware: Source labware to look up.target::Labware: Target labware to look up.
Returns
(src_inds, tgt_inds): A 2-tuple of vectors:src_inds: index selector(s) associated withsourcetgt_inds: index selector(s) associated withtarget
These are intended to be used together for indexing transfer arrays/tensors.
Throws
ArgumentError: Ifsourceis not insource_labware(pc)ortargetis not intarget_labware(pc).
Pourfecto.transfers — Method
Pourfecto.transfers_by_config — Method
transfers_by_config(pc::Pourcast) -> Vector{Matrix{Float64}}Compute well-to-well transfer volumes per configuration.
This function aggregates the global flow matrix flows(pc) into per-configuration transfer matrices between source wells and target wells.
For each configuration c in configs(pc), it returns an S×T matrix trfs_by_config[c] where:
Sis the total number of source wells across all source labware.Tis the total number of target wells across all target labware.- Entry
trfs_by_config[c][s, t]equals the sum of all flows (fromflows(pc)) along aspiration/dispense node pairs that:- connect source well
sto target wellt(viaPourfecto.compute_flow_connections), and - belong to configuration
c(i.e., both nodes have.configuration == cons[c]).
- connect source well
Arguments
pc::Pourcast: A pour/transfer plan providing configurations, labware, well names, and a global flow matrix viaflows(pc).
Returns
Vector{Matrix{Float64}}: A length-Cvector whereC == length(configs(pc)). Each element is anS×Tdense matrix of aggregated transfer amounts.
Pourfecto.write_instrument_files — Function
Compiling function for Mantis