BMS.Mastermix_Maker Function¶
This function can be used to automatedly generate mastermixes based on source materials in a list of destination labware layout objects, and user-defined parameters.
This function can be used to automatically generate mastermixes for a given list of destination labware layouts. The mastermixes are generated by finding common source reagents across destination wells, and grouping them together in the minimal amount of mastermixes. The mastermixes generated are stored in BMS.labware_layout objects and also returned as a list of BMS.Mastermix objects.
The exact composition of the mastermixes generated can be influenced by through the use of arguments listed above. In some cases, these arguments may provide too many constraints and result in an impossible situation where mastermixes cannot be generated. To help ensure many different combinations are attempted, there is some randomness within the function. This randomness can be removed by supplying a specific seed, which ensures that the same mastermixes are generated each time.
Check out the full documentation here.
Setting Up¶
The first step is to import the BiomationScripter module as shown below
import BiomationScripter as bms
Create Destination Labware Layout¶
The Mastermix_Maker function requires at least one Labware_Layout object which defines the final state of the destination labware for which the mastermixes will be generated for. This can be defined using the Labware_Layout object, or imported from a file using the Import_Labware_Layout function.
Destination_Layout = bms.Labware_Layout("Destination", "greiner655087_96_wellplate_340ul")
Destination_Layout.define_format(8, 12)
well_set_1 = bms.well_range(Labware_Format = Destination_Layout, Wells = "A1:A12")
well_set_2 = bms.well_range(Labware_Format = Destination_Layout, Wells = "A1:A6")
well_set_3 = bms.well_range(Labware_Format = Destination_Layout, Wells = "A7:A12")
well_set_4 = bms.well_range(Labware_Format = Destination_Layout, Wells = "A1:A3")
well_set_5 = bms.well_range(Labware_Format = Destination_Layout, Wells = "A4:A6")
well_set_6 = bms.well_range(Labware_Format = Destination_Layout, Wells = "A7:A9")
well_set_7 = bms.well_range(Labware_Format = Destination_Layout, Wells = "A10:A12")
for well in well_set_1:
Destination_Layout.add_content(well, "LB", 80)
for well in well_set_2:
Destination_Layout.add_content(well, "Cells 1", 19)
for well in well_set_3:
Destination_Layout.add_content(well, "Cells 2", 19)
for well in well_set_4 + well_set_6:
Destination_Layout.add_content(well, "Water", 1)
for well in well_set_5 + well_set_7:
Destination_Layout.add_content(well, "Inducer", 1)
Destination_Layout.print()
Information for Destination
Plate Type: greiner655087_96_wellplate_340ul
Well Volume(uL) Liquid Class Reagent
A1 80.0 Unknown LB
A1 19.0 Unknown Cells 1
A1 1.0 Unknown Water
A2 80.0 Unknown LB
A2 19.0 Unknown Cells 1
A2 1.0 Unknown Water
A3 80.0 Unknown LB
A3 19.0 Unknown Cells 1
A3 1.0 Unknown Water
A4 80.0 Unknown LB
A4 19.0 Unknown Cells 1
A4 1.0 Unknown Inducer
A5 80.0 Unknown LB
A5 19.0 Unknown Cells 1
A5 1.0 Unknown Inducer
A6 80.0 Unknown LB
A6 19.0 Unknown Cells 1
A6 1.0 Unknown Inducer
A7 80.0 Unknown LB
A7 19.0 Unknown Cells 2
A7 1.0 Unknown Water
A8 80.0 Unknown LB
A8 19.0 Unknown Cells 2
A8 1.0 Unknown Water
A9 80.0 Unknown LB
A9 19.0 Unknown Cells 2
A9 1.0 Unknown Water
A10 80.0 Unknown LB
A10 19.0 Unknown Cells 2
A10 1.0 Unknown Inducer
A11 80.0 Unknown LB
A11 19.0 Unknown Cells 2
A11 1.0 Unknown Inducer
A12 80.0 Unknown LB
A12 19.0 Unknown Cells 2
A12 1.0 Unknown Inducer
'A1\t80.0\t\tUnknown\t\tLB\nA1\t19.0\t\tUnknown\t\tCells 1\nA1\t1.0\t\tUnknown\t\tWater\nA2\t80.0\t\tUnknown\t\tLB\nA2\t19.0\t\tUnknown\t\tCells 1\nA2\t1.0\t\tUnknown\t\tWater\nA3\t80.0\t\tUnknown\t\tLB\nA3\t19.0\t\tUnknown\t\tCells 1\nA3\t1.0\t\tUnknown\t\tWater\nA4\t80.0\t\tUnknown\t\tLB\nA4\t19.0\t\tUnknown\t\tCells 1\nA4\t1.0\t\tUnknown\t\tInducer\nA5\t80.0\t\tUnknown\t\tLB\nA5\t19.0\t\tUnknown\t\tCells 1\nA5\t1.0\t\tUnknown\t\tInducer\nA6\t80.0\t\tUnknown\t\tLB\nA6\t19.0\t\tUnknown\t\tCells 1\nA6\t1.0\t\tUnknown\t\tInducer\nA7\t80.0\t\tUnknown\t\tLB\nA7\t19.0\t\tUnknown\t\tCells 2\nA7\t1.0\t\tUnknown\t\tWater\nA8\t80.0\t\tUnknown\t\tLB\nA8\t19.0\t\tUnknown\t\tCells 2\nA8\t1.0\t\tUnknown\t\tWater\nA9\t80.0\t\tUnknown\t\tLB\nA9\t19.0\t\tUnknown\t\tCells 2\nA9\t1.0\t\tUnknown\t\tWater\nA10\t80.0\t\tUnknown\t\tLB\nA10\t19.0\t\tUnknown\t\tCells 2\nA10\t1.0\t\tUnknown\t\tInducer\nA11\t80.0\t\tUnknown\t\tLB\nA11\t19.0\t\tUnknown\t\tCells 2\nA11\t1.0\t\tUnknown\t\tInducer\nA12\t80.0\t\tUnknown\t\tLB\nA12\t19.0\t\tUnknown\t\tCells 2\nA12\t1.0\t\tUnknown\t\tInducer\n'
Define the Mastermix Labware¶
Mastermix_Maker also requies as single Labware_Layout object which defines the labware in which the mastermixes will be prepared. It is essential that the format (number of rows and columns) and the available wells are defined, otherwise Mastermix_Maker will raise errors.
Mastermix_Layout = bms.Labware_Layout("Mastermix", "3dprinted_24_tuberack_1500ul")
Mastermix_Layout.define_format(4, 6)
Mastermix_Layout.set_available_wells()
Mastermix Parameters¶
There are a number of parameters which can be used to influence the composition of the mastermixes created. Some of these are optional, and some are compulsory. The required parameters are:
- Maximum_Mastermix_Volume: The maximum volume (in uL) for each mastermix - this ensures that mastermixes don't overflow the well or tube they are prepared in
- Min_Transfer_Volume: The minimum transfer volume (in uL) to allow - this can be used to make sure that reagents which would usually be added to the destination labware in quantities below this volume are included in the mastermixes
- Extra_Reactions: The number of extra reactions each mastermix should include - this can help account for pipetting errors and dead volumes to ensure that mastermixes do not run out - note also that this can be a fraction of a reaction(e.g. 0.8 extra reactions)
- Seed: The
Mastermix_Makerfunction can use some amount of randomness to help find solutions for complex situations, to enable this set the Seed toNone- a specific seed can also be supplied to ensure the mastermixes generated are always the same
Maximum_Mastermix_Volume = 1000 # uL
Min_Transfer_Volume = 5 # uL
Extra_Reactions = 1
Seed = 1
For now, we'll ignore the optional parameters
Generating the Mastermixes¶
The Mastermix_Maker function can now be called using the information we've defined above. Once called, the function returns four variables:
- Mastermixes: A list of
Mastermixobjects which hold information about each mastermix - Seed: The seed used to generate the mastermixes - this will only be different to the input
SeedifNonewas specified - Destination_Layouts: This will return the same objects supplied to
Destination_Layouts, but the contents will have been modified to now include the mastermixes - Mastermix_Layouts: A list of
Labware_Layoutobjects, created using the object supplied toMastermix_Layoutas a template, containing the source material for required for each mastermix generated
Mastermixes, Seed, Destination_Layouts, Mastermix_Layouts = bms.Mastermix_Maker(
Destination_Layouts = [Destination_Layout],
Mastermix_Layout = Mastermix_Layout,
Maximum_Mastermix_Volume = Maximum_Mastermix_Volume,
Min_Transfer_Volume = Min_Transfer_Volume,
Extra_Reactions=Extra_Reactions,
Seed = Seed
)
Determining mastermixes, this may take a while...
Checking the Results¶
We can check what mastermixes were generated by looking at the Mastermixes variable returned by the function in the following ways:
for mm in Mastermixes:
print(mm.name)
print(mm.wells)
print(mm.reagents, "\n")
Inducer_vol_1.0:LB_vol_80.0
{'0_A12', '0_A4', '0_A6', '0_A11', '0_A10', '0_A5'}
['Inducer_vol_1.0', 'LB_vol_80.0']
Water_vol_1.0:LB_vol_80.0
{'0_A2', '0_A9', '0_A1', '0_A7', '0_A8', '0_A3'}
['Water_vol_1.0', 'LB_vol_80.0']
We can also see the mastermixes in the Mastermix_Layouts variable:
for layout in Mastermix_Layouts:
layout.print()
Information for Mastermix
Plate Type: 3dprinted_24_tuberack_1500ul
Well Volume(uL) Liquid Class Reagent
A1 7.0 Unknown Inducer
A1 560.0 Unknown LB
A2 7.0 Unknown Water
A2 560.0 Unknown LB
The names of the mastermixes are stored in the well_labels attribute:
for layout in Mastermix_Layouts:
print(layout.name)
for well in layout.well_labels:
print("> ", layout.well_labels[well])
Mastermix > Inducer_vol_1.0:LB_vol_80.0 > Water_vol_1.0:LB_vol_80.0
And also check how the Destination labware layout has changed. Check here to compare this to how the destination layout looked before.
for layout in Destination_Layouts:
layout.print()
Information for Destination
Plate Type: greiner655087_96_wellplate_340ul
Well Volume(uL) Liquid Class Reagent
A1 19.0 Unknown Cells 1
A1 81.0 Unknown Water_vol_1.0:LB_vol_80.0
A2 19.0 Unknown Cells 1
A2 81.0 Unknown Water_vol_1.0:LB_vol_80.0
A3 19.0 Unknown Cells 1
A3 81.0 Unknown Water_vol_1.0:LB_vol_80.0
A4 19.0 Unknown Cells 1
A4 81.0 Unknown Inducer_vol_1.0:LB_vol_80.0
A5 19.0 Unknown Cells 1
A5 81.0 Unknown Inducer_vol_1.0:LB_vol_80.0
A6 19.0 Unknown Cells 1
A6 81.0 Unknown Inducer_vol_1.0:LB_vol_80.0
A7 19.0 Unknown Cells 2
A7 81.0 Unknown Water_vol_1.0:LB_vol_80.0
A8 19.0 Unknown Cells 2
A8 81.0 Unknown Water_vol_1.0:LB_vol_80.0
A9 19.0 Unknown Cells 2
A9 81.0 Unknown Water_vol_1.0:LB_vol_80.0
A10 19.0 Unknown Cells 2
A10 81.0 Unknown Inducer_vol_1.0:LB_vol_80.0
A11 19.0 Unknown Cells 2
A11 81.0 Unknown Inducer_vol_1.0:LB_vol_80.0
A12 19.0 Unknown Cells 2
A12 81.0 Unknown Inducer_vol_1.0:LB_vol_80.0
Finally, we can check the Seed used - this will be the same as the seed we provided:
Seed
1
Specifying Preferential Reagents¶
In this situation, the Cells were not used in the mastermixes as this would have resulted in a larger number of mastermixes generated. However, we can use the Preferential_Reagents argument to indicate that we'd rather Cells were included into the mastermixes, even if it is suboptimal. It is important to note that if a solution could not be found which includes these reagents, maastermixes will instead be generated without them and an error WILL NOT be raised.
Destination_Layout = bms.Labware_Layout("Destination", "greiner655087_96_wellplate_340ul")
Destination_Layout.define_format(8, 12)
well_set_1 = bms.well_range(Labware_Format = Destination_Layout, Wells = "A1:A12")
well_set_2 = bms.well_range(Labware_Format = Destination_Layout, Wells = "A1:A6")
well_set_3 = bms.well_range(Labware_Format = Destination_Layout, Wells = "A7:A12")
well_set_4 = bms.well_range(Labware_Format = Destination_Layout, Wells = "A1:A3")
well_set_5 = bms.well_range(Labware_Format = Destination_Layout, Wells = "A4:A6")
well_set_6 = bms.well_range(Labware_Format = Destination_Layout, Wells = "A7:A9")
well_set_7 = bms.well_range(Labware_Format = Destination_Layout, Wells = "A10:A12")
for well in well_set_1:
Destination_Layout.add_content(well, "LB", 80)
for well in well_set_2:
Destination_Layout.add_content(well, "Cells 1", 19)
for well in well_set_3:
Destination_Layout.add_content(well, "Cells 2", 19)
for well in well_set_4 + well_set_6:
Destination_Layout.add_content(well, "Water", 1)
for well in well_set_5 + well_set_7:
Destination_Layout.add_content(well, "Inducer", 1)
Mastermix_Layout = bms.Labware_Layout("Mastermix", "3dprinted_24_tuberack_1500ul")
Mastermix_Layout.define_format(4, 6)
Mastermix_Layout.set_available_wells()
Maximum_Mastermix_Volume = 1000 # uL
Min_Transfer_Volume = 5 # uL
Extra_Reactions = 1
Seed = 1
Preferential_Reagents = ["Cells 1", "Cells 2"]
Mastermixes, Seed, Destination_Layouts, Mastermix_Layouts = bms.Mastermix_Maker(
Destination_Layouts = [Destination_Layout],
Mastermix_Layout = Mastermix_Layout,
Maximum_Mastermix_Volume = Maximum_Mastermix_Volume,
Min_Transfer_Volume = Min_Transfer_Volume,
Extra_Reactions=Extra_Reactions,
Preferential_Reagents = Preferential_Reagents,
Seed = Seed
)
Determining mastermixes, this may take a while...
We can now see that the cells were used instead of the LB, and four mastermixes were generated instead of 2
for mm in Mastermixes:
print(mm.name)
print(mm.wells)
print(mm.reagents, "\n")
Inducer_vol_1.0:Cells 1_vol_19.0
{'0_A4', '0_A6', '0_A5'}
['Inducer_vol_1.0', 'Cells 1_vol_19.0']
Inducer_vol_1.0:Cells 2_vol_19.0
{'0_A12', '0_A11', '0_A10'}
['Inducer_vol_1.0', 'Cells 2_vol_19.0']
Water_vol_1.0:Cells 1_vol_19.0
{'0_A1', '0_A2', '0_A3'}
['Water_vol_1.0', 'Cells 1_vol_19.0']
Water_vol_1.0:Cells 2_vol_19.0
{'0_A7', '0_A8', '0_A9'}
['Water_vol_1.0', 'Cells 2_vol_19.0']
for layout in Mastermix_Layouts:
layout.print()
Information for Mastermix
Plate Type: 3dprinted_24_tuberack_1500ul
Well Volume(uL) Liquid Class Reagent
A1 5.0 Unknown Inducer
A1 95.0 Unknown Cells 1
A2 5.0 Unknown Inducer
A2 95.0 Unknown Cells 2
A3 5.0 Unknown Water
A3 95.0 Unknown Cells 1
A4 5.0 Unknown Water
A4 95.0 Unknown Cells 2
for layout in Mastermix_Layouts:
print(layout.name)
for well in layout.well_labels:
print("> ", layout.well_labels[well])
Mastermix > Inducer_vol_1.0:Cells 1_vol_19.0 > Inducer_vol_1.0:Cells 2_vol_19.0 > Water_vol_1.0:Cells 1_vol_19.0 > Water_vol_1.0:Cells 2_vol_19.0
Excluded Combinations¶
It is also possible to include combinations of reagents which shouldn't be combined at the mastermix preparation stage. This could be useful in situations where two or more reagents shouldn't be combined until the last moment, such as a substrate and enzyme, for example.
Here, we'll specify that the LB and the inducer shouldn't be combined into mastermixes:
Destination_Layout = bms.Labware_Layout("Destination", "greiner655087_96_wellplate_340ul")
Destination_Layout.define_format(8, 12)
well_set_1 = bms.well_range(Labware_Format = Destination_Layout, Wells = "A1:A12")
well_set_2 = bms.well_range(Labware_Format = Destination_Layout, Wells = "A1:A6")
well_set_3 = bms.well_range(Labware_Format = Destination_Layout, Wells = "A7:A12")
well_set_4 = bms.well_range(Labware_Format = Destination_Layout, Wells = "A1:A3")
well_set_5 = bms.well_range(Labware_Format = Destination_Layout, Wells = "A4:A6")
well_set_6 = bms.well_range(Labware_Format = Destination_Layout, Wells = "A7:A9")
well_set_7 = bms.well_range(Labware_Format = Destination_Layout, Wells = "A10:A12")
for well in well_set_1:
Destination_Layout.add_content(well, "LB", 80)
for well in well_set_2:
Destination_Layout.add_content(well, "Cells 1", 19)
for well in well_set_3:
Destination_Layout.add_content(well, "Cells 2", 19)
for well in well_set_4 + well_set_6:
Destination_Layout.add_content(well, "Water", 1)
for well in well_set_5 + well_set_7:
Destination_Layout.add_content(well, "Inducer", 1)
Mastermix_Layout = bms.Labware_Layout("Mastermix", "3dprinted_24_tuberack_1500ul")
Mastermix_Layout.define_format(4, 6)
Mastermix_Layout.set_available_wells()
Maximum_Mastermix_Volume = 1000 # uL
Min_Transfer_Volume = 5 # uL
Extra_Reactions = 1
Seed = 1
Excluded_Combinations = [
["LB", "Inducer"]
]
Mastermixes, Seed, Destination_Layouts, Mastermix_Layouts = bms.Mastermix_Maker(
Destination_Layouts = [Destination_Layout],
Mastermix_Layout = Mastermix_Layout,
Maximum_Mastermix_Volume = Maximum_Mastermix_Volume,
Min_Transfer_Volume = Min_Transfer_Volume,
Extra_Reactions=Extra_Reactions,
Excluded_Combinations = Excluded_Combinations,
Seed = Seed
)
Determining mastermixes, this may take a while...
We can see that now three mastermixes have been generated, where the Inducer is never mixed with the LB media:
for mm in Mastermixes:
print(mm.name)
print(mm.wells)
print(mm.reagents, "\n")
Inducer_vol_1.0:Cells 1_vol_19.0
{'0_A4', '0_A6', '0_A5'}
['Inducer_vol_1.0', 'Cells 1_vol_19.0']
Inducer_vol_1.0:Cells 2_vol_19.0
{'0_A12', '0_A11', '0_A10'}
['Inducer_vol_1.0', 'Cells 2_vol_19.0']
Water_vol_1.0:LB_vol_80.0
{'0_A2', '0_A9', '0_A1', '0_A7', '0_A8', '0_A3'}
['Water_vol_1.0', 'LB_vol_80.0']
for layout in Mastermix_Layouts:
layout.print()
Information for Mastermix
Plate Type: 3dprinted_24_tuberack_1500ul
Well Volume(uL) Liquid Class Reagent
A1 5.0 Unknown Inducer
A1 95.0 Unknown Cells 1
A2 5.0 Unknown Inducer
A2 95.0 Unknown Cells 2
A3 7.0 Unknown Water
A3 560.0 Unknown LB
for layout in Mastermix_Layouts:
print(layout.name)
for well in layout.well_labels:
print("> ", layout.well_labels[well])
Mastermix > Inducer_vol_1.0:Cells 1_vol_19.0 > Inducer_vol_1.0:Cells 2_vol_19.0 > Water_vol_1.0:LB_vol_80.0
Impossible Situations¶
There can be situations where too many restrictions are placed on the Mastermix_Maker such at it is impossible to meet all criteria.
To illustrate this, we'll add in two excluded combinations:
- Inducer with LB
- Inducer with Cells 1
- Inducer with Cells 2
In this case, the Inducer cannot be mixed with any reagent, which means it will need to be added to the destination wells directly. However, the volume of Inducer per well is 1 uL, which is below the minimum transfer volume of 5 uL we specified previously. Therefore, there are no valid situations:
Destination_Layout = bms.Labware_Layout("Destination", "greiner655087_96_wellplate_340ul")
Destination_Layout.define_format(8, 12)
well_set_1 = bms.well_range(Labware_Format = Destination_Layout, Wells = "A1:A12")
well_set_2 = bms.well_range(Labware_Format = Destination_Layout, Wells = "A1:A6")
well_set_3 = bms.well_range(Labware_Format = Destination_Layout, Wells = "A7:A12")
well_set_4 = bms.well_range(Labware_Format = Destination_Layout, Wells = "A1:A3")
well_set_5 = bms.well_range(Labware_Format = Destination_Layout, Wells = "A4:A6")
well_set_6 = bms.well_range(Labware_Format = Destination_Layout, Wells = "A7:A9")
well_set_7 = bms.well_range(Labware_Format = Destination_Layout, Wells = "A10:A12")
for well in well_set_1:
Destination_Layout.add_content(well, "LB", 80)
for well in well_set_2:
Destination_Layout.add_content(well, "Cells 1", 19)
for well in well_set_3:
Destination_Layout.add_content(well, "Cells 2", 19)
for well in well_set_4 + well_set_6:
Destination_Layout.add_content(well, "Water", 1)
for well in well_set_5 + well_set_7:
Destination_Layout.add_content(well, "Inducer", 1)
Mastermix_Layout = bms.Labware_Layout("Mastermix", "3dprinted_24_tuberack_1500ul")
Mastermix_Layout.define_format(4, 6)
Mastermix_Layout.set_available_wells()
Maximum_Mastermix_Volume = 1000 # uL
Min_Transfer_Volume = 5 # uL
Extra_Reactions = 1
Seed = None
Excluded_Combinations = [
["LB", "Inducer"],
["Cells 1", "Inducer"],
["Cells 2", "Inducer"]
]
Mastermixes, Seed, Destination_Layouts, Mastermix_Layouts = bms.Mastermix_Maker(
Destination_Layouts = [Destination_Layout],
Mastermix_Layout = Mastermix_Layout,
Maximum_Mastermix_Volume = Maximum_Mastermix_Volume,
Min_Transfer_Volume = Min_Transfer_Volume,
Extra_Reactions=Extra_Reactions,
Excluded_Combinations = Excluded_Combinations,
Seed = Seed
)
Determining mastermixes, this may take a while...
--------------------------------------------------------------------------- MastermixError Traceback (most recent call last) ~\anaconda3\lib\site-packages\BiomationScripter\__init__.py in Mastermix_Maker(Destination_Layouts, Mastermix_Layout, Maximum_Mastermix_Volume, Min_Transfer_Volume, Extra_Reactions, Excluded_Reagents, Excluded_Combinations, Preferential_Reagents, Seed) 1450 if No_Solution: -> 1451 raise MastermixError("No solution could be found with these constraints.") 1452 else: MastermixError: No solution could be found with these constraints. During handling of the above exception, another exception occurred: MastermixError Traceback (most recent call last) ~\AppData\Local\Temp/ipykernel_35284/4268555091.py in <module> 40 ] 41 ---> 42 Mastermixes, Seed, Destination_Layouts, Mastermix_Layouts = bms.Mastermix_Maker( 43 Destination_Layouts = [Destination_Layout], 44 Mastermix_Layout = Mastermix_Layout, ~\anaconda3\lib\site-packages\BiomationScripter\__init__.py in Mastermix_Maker(Destination_Layouts, Mastermix_Layout, Maximum_Mastermix_Volume, Min_Transfer_Volume, Extra_Reactions, Excluded_Reagents, Excluded_Combinations, Preferential_Reagents, Seed) 1474 if not First_Attempt: 1475 if Seed > 1000: -> 1476 raise MastermixError( 1477 """ 1478 No solution could be found with these constraints. Try one of the following options: MastermixError: No solution could be found with these constraints. Try one of the following options: > Decrease the minimum transfer volume (if specified) > Decrease the stock concentration of highly concentrated source material > Use a mastermix labware with a higher well capacity (especially when there are a lot of samples)