diff --git a/assets/instructions/protocol-1-instructions.Rmd b/assets/instructions/protocol-1-instructions.Rmd index b2f71d3..1f30ce3 100755 --- a/assets/instructions/protocol-1-instructions.Rmd +++ b/assets/instructions/protocol-1-instructions.Rmd @@ -1,5 +1,5 @@ --- -title: "Instructions" +title: "APEX Instructions" output: pdf_document params: json_path: NULL @@ -13,28 +13,26 @@ library(knitr) json_data <- fromJSON(file = params$json_path) ``` \vspace{-1.5cm} -## Protocol 1: Heat shock transformations +## Protocol 1: Heat Shock Transformations in OT-2 ### Overview -DNA is transferred to competent cells. -Pre heat-shock, the cells and added DNA are incubated at `r json_data$pre_shock_incubation_temp` °C for `r json_data$pre_shock_incubation_time` minutes. -Heat-shock is carried out at `r json_data$heat_shock_temp` °C for `r json_data$heat_shock_time` seconds. -Post heat-shock, the transformed cells are incubated at `r json_data$post_shock_incubation_temp` °C for `r json_data$post_shock_incubation_time` minutes. -The recovery medium is added and cells are incubated at `r json_data$recovery_temp`°C for `r json_data$recovery_time` minutes. +Competent cells are distributed into destination plate. +DNA is added to competent cells. +Pre heat shock, the cells and added DNA are incubated at `r json_data$pre_shock_incubation_temp` °C for `r json_data$pre_shock_incubation_time` minutes. +Heat shock is carried out at `r json_data$heat_shock_temp` °C for `r json_data$heat_shock_time` seconds. +Post heat shock, the cells are incubated at `r json_data$post_shock_incubation_temp` °C for `r json_data$post_shock_incubation_time` minutes. +The recovery medium is added and cells are incubated at `r json_data$recovery_temp` °C for `r json_data$recovery_time` minutes. ### Preparation -Prepare the reagents and labware according to the below diagrams. -Volumes (uL) indicate how much of reagents will be used, so add additional volume. +Prepare the necessary reagents and labware as outlined in the layout provided below. +Listed volumes are in `r "$\\mu$L"` and indicate the amount of each reagent required. +Ensure to include an additional volume. ```{r import-labware-images, results='asis', echo=FALSE} -# Read all image files from the directory image_files <- list.files(path = params$labware_images_dir, pattern = "\\.png$", full.names = TRUE) -# Sort files numerically and alphabetically image_files <- sort(image_files) -# Print images in Markdown format, 2 per row for (i in seq_along(image_files)) { - # Start a new line for every pair of images if (i %% 2 == 1 && i > 1) { cat('\\newline\n') } @@ -48,10 +46,10 @@ for (i in seq_along(image_files)) { ``` ### Deck Loading -Check that `r json_data$right_pipette_name` is in the right mount and `r json_data$left_pipette_name` is in the left mount. -**Slot `r json_data$right_pipette_tiprack_slot`** load `r json_data$right_pipette_tiprack_name` for the `r json_data$right_pipette_name` pipette. -**Slot `r json_data$left_pipette_tiprack_slot`** load `r json_data$left_pipette_tiprack_name` for the `r json_data$left_pipette_name` pipette. -**Slot `r json_data$dna_plate_slot`** load `r json_data$dna_plate_name` containing DNA. -**Slot `r json_data$cells_plate_slot`** load `r json_data$cells_plate_name` containing competent cells. -**Slot `r json_data$media_plate_slot`** load `r json_data$media_plate_name` containing recovery medium. -**Slot 7,8,10,11** load a thermocycler and turn it on. Load `r json_data$transformation_plate_name` into the thermocycler when instructed on the screen. \ No newline at end of file +Check that `r json_data$right_pipette_name` is in the right mount and `r json_data$left_pipette_name` is in the left mount. +**Slot `r json_data$right_pipette_tiprack_slot`** load `r json_data$right_pipette_tiprack_name` for the `r json_data$right_pipette_name` pipette. +**Slot `r json_data$left_pipette_tiprack_slot`** load `r json_data$left_pipette_tiprack_name` for the `r json_data$left_pipette_name` pipette. +**Slot `r json_data$dna_plate_slot`** load `r json_data$dna_plate_name` containing DNA. +**Slot `r json_data$cells_plate_slot`** load `r json_data$cells_plate_name` containing competent cells. +**Slot `r json_data$media_plate_slot`** load `r json_data$media_plate_name` containing recovery medium. +**Slot 7,8,10,11** load a thermocycler and turn it on. Load `r json_data$transformation_plate_name` into the thermocycler when instructed on the screen. \ No newline at end of file diff --git a/assets/instructions/protocol-2-instructions.Rmd b/assets/instructions/protocol-2-instructions.Rmd index 22bb77a..645b1dd 100755 --- a/assets/instructions/protocol-2-instructions.Rmd +++ b/assets/instructions/protocol-2-instructions.Rmd @@ -1,5 +1,5 @@ --- -title: "Instructions" +title: "APEX Instructions" output: pdf_document params: json_path: NULL @@ -13,28 +13,24 @@ library(knitr) json_data <- fromJSON(file = params$json_path) ``` \vspace{-1.5cm} -## Protocol 2: Colony selection +## Protocol 2: Colony Selection in OT-2 ### Overview -Transformed cells are spotted on the total of `r length(json_data$agar_plate_slot) ` agar plates. +Cells are spotted on the total of `r length(json_data$agar_plate_slot) ` agar plates. The pipette aspirates additional `r json_data$additional_volume` $\mu$L of transformed cells. -The spotting height above the agar is set at `r json_data$spotting_height` mm. +The spotting height above the agar is set at `r json_data$spotting_height` (mm). The agar height is calculated automatically per plate based on: -the plate weight without agar and with agar (g), -and agar density of `r json_data$agar_density`($g mm^{-3}$). +the plate weight without (`r json_data$empty_agar_plate_weight` g) and with agar (`r json_data$agar_plate_weight` g), +and agar density of `r json_data$agar_density` ($g cm^{-3}$). ### Preparation -The plates are spotted in uL according to the layout below. +The plates are spotted in `r "$\\mu$L"` according to the layout below. ```{r import-labware-images, results='asis', echo=FALSE} -# Read all image files from the directory image_files <- list.files(path = params$labware_images_dir, pattern = "\\.png$", full.names = TRUE) -# Sort files numerically and alphabetically image_files <- sort(image_files) -# Print images in Markdown format, 2 per row for (i in seq_along(image_files)) { - # Start a new line for every pair of images if (i %% 2 == 1 && i > 1) { cat('\\newline\n') } @@ -48,7 +44,7 @@ for (i in seq_along(image_files)) { ``` ### Deck Loading -Check that `r json_data$pipette_name` is in the `r json_data$pipette_mount` mount. -**Slot `r json_data$tiprack_slots`** load `r json_data$tiprack_name` for the `r json_data$pipette_name` pipette. -**Slot `r json_data$agar_plate_slot`** load `r json_data$agar_plate_name` containing agar. -**Slot `r json_data$source_plate_slot`** load `r json_data$source_plate_name` containing transformed cells. \ No newline at end of file +Check that `r json_data$pipette_name` is in the `r json_data$pipette_mount` mount. +**Slot `r json_data$tiprack_slots`** load `r json_data$tiprack_name` for the `r json_data$pipette_name` pipette. +**Slot `r json_data$source_plate_slot`** load `r json_data$source_plate_name` containing cells to be spotted. +**Slot `r json_data$agar_plate_slot`** load `r json_data$agar_plate_name` with agar. diff --git a/assets/instructions/protocol-3-instructions.Rmd b/assets/instructions/protocol-3-instructions.Rmd index c0634a4..e48a162 100755 --- a/assets/instructions/protocol-3-instructions.Rmd +++ b/assets/instructions/protocol-3-instructions.Rmd @@ -1,5 +1,5 @@ --- -title: "Instructions" +title: "APEX Instructions" output: pdf_document params: json_path: NULL @@ -16,25 +16,22 @@ json_data <- fromJSON(file = params$json_path) ## Protocol 3: Colony Sampling in OT-2 ### Overview -The colonies are sampled using a pipette tip and transferred to destination plate containing fresh media supplemented with appropriate antibiotic. -The robot samples colonies from total of `r length(json_data$agar_plate_slot) ` agar plates. -The picking height into the agar is set at `r json_data$agar_pierce_depth` mm. +Media with supplemented antibtiotic is distributed into the destination plate. +The colonies are sampled using a pipette tip and transferred to destination plate. +Colonies are sampled from total of `r length(json_data$agar_plate_slot) ` agar plates. +The picking height into the agar is set at `r json_data$agar_pierce_depth` (mm). The agar height is calculated automatically per plate based on: -the plate weight without agar and with agar (g), -and agar density of `r json_data$agar_density`($g mm^{-3}$). +the plate weight without (`r json_data$empty_agar_plate_weight` g) and with agar (`r json_data$agar_plate_weight` g), +and agar density of `r json_data$agar_density` ($g cm^{-3}$). ### Preparation The colonies are sampled according to the plate layout below. ```{r import-labware-images, results='asis', echo=FALSE} -# Read all image files from the directory image_files <- list.files(path = params$labware_images_dir, pattern = "\\.png$", full.names = TRUE) -# Sort files numerically and alphabetically image_files <- sort(image_files) -# Print images in Markdown format, 2 per row for (i in seq_along(image_files)) { - # Start a new line for every pair of images if (i %% 2 == 1 && i > 1) { cat('\\newline\n') } @@ -48,9 +45,9 @@ for (i in seq_along(image_files)) { ``` ### Deck Loading -Check that `r json_data$right_pipette_name` is in the right mount and `r json_data$left_pipette_name` is in the left mount. -**Slot `r json_data$right_pipette_tiprack_slot`** load `r json_data$right_pipette_tiprack_name` for the `r json_data$right_pipette_name` pipette. -**Slot `r json_data$left_pipette_tiprack_slot`** load `r json_data$left_pipette_tiprack_name` for the `r json_data$left_pipette_name` pipette. -**Slot `r json_data$media_plate_slot`** load `r json_data$media_plate_name` containing fresh media with antibiotic. -**Slot `r json_data$agar_plate_slot`** load `r json_data$agar_plate_name` containing agar with developed colonies. -**Slot `r json_data$destination_plate_slot`** load `r json_data$destination_plate_name` where fresh media will be distributed and sampled cells propagated. +Check that `r json_data$right_pipette_name` is in the right mount and `r json_data$left_pipette_name` is in the left mount. +**Slot `r json_data$right_pipette_tiprack_slot`** load `r json_data$right_pipette_tiprack_name` for the `r json_data$right_pipette_name` pipette. +**Slot `r json_data$left_pipette_tiprack_slot`** load `r json_data$left_pipette_tiprack_name` for the `r json_data$left_pipette_name` pipette. +**Slot `r json_data$media_plate_slot`** load `r json_data$media_plate_name` containing fresh media with antibiotic. +**Slot `r json_data$agar_plate_slot`** load `r json_data$agar_plate_name` containing agar with developed colonies. +**Slot `r json_data$destination_plate_slot`** load `r json_data$destination_plate_name` where fresh media will be distributed and sampled cells propagated. diff --git a/assets/instructions/protocol-4-instructions.Rmd b/assets/instructions/protocol-4-instructions.Rmd index a66f0bf..c007ca7 100755 --- a/assets/instructions/protocol-4-instructions.Rmd +++ b/assets/instructions/protocol-4-instructions.Rmd @@ -13,7 +13,7 @@ library(knitr) json_data <- fromJSON(file = params$json_path) ``` \vspace{-1.5cm} -## Protocol 4: Protein Expression induction in OT-2 +## Protocol 4: Protein Expression Induction in OT-2 ### Overview Fresh antibiotic media is distributed into the destination plate, followed by aliquoting and inoculating overnight cultures into this media. diff --git a/assets/labware/nunc96grid_96_wellplate_10ul copy.json b/assets/labware/nunc96grid_96_wellplate_10ul copy.json deleted file mode 100755 index 8bd54d2..0000000 --- a/assets/labware/nunc96grid_96_wellplate_10ul copy.json +++ /dev/null @@ -1 +0,0 @@ -{"ordering":[["A1","B1","C1","D1","E1","F1","G1","H1"],["A2","B2","C2","D2","E2","F2","G2","H2"],["A3","B3","C3","D3","E3","F3","G3","H3"],["A4","B4","C4","D4","E4","F4","G4","H4"],["A5","B5","C5","D5","E5","F5","G5","H5"],["A6","B6","C6","D6","E6","F6","G6","H6"],["A7","B7","C7","D7","E7","F7","G7","H7"],["A8","B8","C8","D8","E8","F8","G8","H8"],["A9","B9","C9","D9","E9","F9","G9","H9"],["A10","B10","C10","D10","E10","F10","G10","H10"],["A11","B11","C11","D11","E11","F11","G11","H11"],["A12","B12","C12","D12","E12","F12","G12","H12"]],"brand":{"brand":"Nunc 96 grid","brandId":[]},"metadata":{"displayName":"Nunc 96 Grid 96 Well Plate 10 µL","displayCategory":"wellPlate","displayVolumeUnits":"µL","tags":[]},"dimensions":{"xDimension":127.8,"yDimension":85.5,"zDimension":14.5},"wells":{"A1":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":11,"y":74.5,"z":2.9},"B1":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":11,"y":65.5,"z":2.9},"C1":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":11,"y":56.5,"z":2.9},"D1":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":11,"y":47.5,"z":2.9},"E1":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":11,"y":38.5,"z":2.9},"F1":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":11,"y":29.5,"z":2.9},"G1":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":11,"y":20.5,"z":2.9},"H1":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":11,"y":11.5,"z":2.9},"A2":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":20.6,"y":74.5,"z":2.9},"B2":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":20.6,"y":65.5,"z":2.9},"C2":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":20.6,"y":56.5,"z":2.9},"D2":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":20.6,"y":47.5,"z":2.9},"E2":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":20.6,"y":38.5,"z":2.9},"F2":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":20.6,"y":29.5,"z":2.9},"G2":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":20.6,"y":20.5,"z":2.9},"H2":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":20.6,"y":11.5,"z":2.9},"A3":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":30.2,"y":74.5,"z":2.9},"B3":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":30.2,"y":65.5,"z":2.9},"C3":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":30.2,"y":56.5,"z":2.9},"D3":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":30.2,"y":47.5,"z":2.9},"E3":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":30.2,"y":38.5,"z":2.9},"F3":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":30.2,"y":29.5,"z":2.9},"G3":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":30.2,"y":20.5,"z":2.9},"H3":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":30.2,"y":11.5,"z":2.9},"A4":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":39.8,"y":74.5,"z":2.9},"B4":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":39.8,"y":65.5,"z":2.9},"C4":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":39.8,"y":56.5,"z":2.9},"D4":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":39.8,"y":47.5,"z":2.9},"E4":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":39.8,"y":38.5,"z":2.9},"F4":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":39.8,"y":29.5,"z":2.9},"G4":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":39.8,"y":20.5,"z":2.9},"H4":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":39.8,"y":11.5,"z":2.9},"A5":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":49.4,"y":74.5,"z":2.9},"B5":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":49.4,"y":65.5,"z":2.9},"C5":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":49.4,"y":56.5,"z":2.9},"D5":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":49.4,"y":47.5,"z":2.9},"E5":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":49.4,"y":38.5,"z":2.9},"F5":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":49.4,"y":29.5,"z":2.9},"G5":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":49.4,"y":20.5,"z":2.9},"H5":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":49.4,"y":11.5,"z":2.9},"A6":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":59,"y":74.5,"z":2.9},"B6":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":59,"y":65.5,"z":2.9},"C6":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":59,"y":56.5,"z":2.9},"D6":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":59,"y":47.5,"z":2.9},"E6":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":59,"y":38.5,"z":2.9},"F6":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":59,"y":29.5,"z":2.9},"G6":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":59,"y":20.5,"z":2.9},"H6":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":59,"y":11.5,"z":2.9},"A7":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":68.6,"y":74.5,"z":2.9},"B7":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":68.6,"y":65.5,"z":2.9},"C7":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":68.6,"y":56.5,"z":2.9},"D7":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":68.6,"y":47.5,"z":2.9},"E7":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":68.6,"y":38.5,"z":2.9},"F7":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":68.6,"y":29.5,"z":2.9},"G7":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":68.6,"y":20.5,"z":2.9},"H7":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":68.6,"y":11.5,"z":2.9},"A8":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":78.2,"y":74.5,"z":2.9},"B8":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":78.2,"y":65.5,"z":2.9},"C8":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":78.2,"y":56.5,"z":2.9},"D8":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":78.2,"y":47.5,"z":2.9},"E8":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":78.2,"y":38.5,"z":2.9},"F8":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":78.2,"y":29.5,"z":2.9},"G8":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":78.2,"y":20.5,"z":2.9},"H8":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":78.2,"y":11.5,"z":2.9},"A9":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":87.8,"y":74.5,"z":2.9},"B9":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":87.8,"y":65.5,"z":2.9},"C9":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":87.8,"y":56.5,"z":2.9},"D9":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":87.8,"y":47.5,"z":2.9},"E9":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":87.8,"y":38.5,"z":2.9},"F9":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":87.8,"y":29.5,"z":2.9},"G9":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":87.8,"y":20.5,"z":2.9},"H9":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":87.8,"y":11.5,"z":2.9},"A10":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":97.4,"y":74.5,"z":2.9},"B10":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":97.4,"y":65.5,"z":2.9},"C10":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":97.4,"y":56.5,"z":2.9},"D10":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":97.4,"y":47.5,"z":2.9},"E10":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":97.4,"y":38.5,"z":2.9},"F10":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":97.4,"y":29.5,"z":2.9},"G10":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":97.4,"y":20.5,"z":2.9},"H10":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":97.4,"y":11.5,"z":2.9},"A11":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":107,"y":74.5,"z":2.9},"B11":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":107,"y":65.5,"z":2.9},"C11":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":107,"y":56.5,"z":2.9},"D11":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":107,"y":47.5,"z":2.9},"E11":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":107,"y":38.5,"z":2.9},"F11":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":107,"y":29.5,"z":2.9},"G11":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":107,"y":20.5,"z":2.9},"H11":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":107,"y":11.5,"z":2.9},"A12":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":116.6,"y":74.5,"z":2.9},"B12":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":116.6,"y":65.5,"z":2.9},"C12":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":116.6,"y":56.5,"z":2.9},"D12":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":116.6,"y":47.5,"z":2.9},"E12":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":116.6,"y":38.5,"z":2.9},"F12":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":116.6,"y":29.5,"z":2.9},"G12":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":116.6,"y":20.5,"z":2.9},"H12":{"depth":11.6,"totalLiquidVolume":10,"shape":"rectangular","xDimension":9.25,"yDimension":9.25,"x":116.6,"y":11.5,"z":2.9}},"groups":[{"metadata":{"wellBottomShape":"flat"},"wells":["A1","B1","C1","D1","E1","F1","G1","H1","A2","B2","C2","D2","E2","F2","G2","H2","A3","B3","C3","D3","E3","F3","G3","H3","A4","B4","C4","D4","E4","F4","G4","H4","A5","B5","C5","D5","E5","F5","G5","H5","A6","B6","C6","D6","E6","F6","G6","H6","A7","B7","C7","D7","E7","F7","G7","H7","A8","B8","C8","D8","E8","F8","G8","H8","A9","B9","C9","D9","E9","F9","G9","H9","A10","B10","C10","D10","E10","F10","G10","H10","A11","B11","C11","D11","E11","F11","G11","H11","A12","B12","C12","D12","E12","F12","G12","H12"]}],"parameters":{"format":"irregular","quirks":[],"isTiprack":false,"isMagneticModuleCompatible":false,"loadName":"nunc96grid_96_wellplate_10ul"},"namespace":"custom_beta","version":1,"schemaVersion":2,"cornerOffsetFromSlot":{"x":0,"y":0,"z":0}} diff --git a/assets/labware/petridish.json b/assets/labware/petridish.json deleted file mode 100644 index 4fd884d..0000000 --- a/assets/labware/petridish.json +++ /dev/null @@ -1,247 +0,0 @@ -{ - "ordering": [ - [ - "A1", - "B1", - "C1", - "D1" - ], - [ - "A2", - "B2", - "C2", - "D2" - ], - [ - "A3", - "B3", - "C3", - "D3" - ], - [ - "A4", - "B4", - "C4", - "D4" - ] - ], - "brand": { - "brand": "Fisherbrand™ ", - "brandId": [ - "12654785" - ] - }, - "metadata": { - "displayName": "Petri Dish 90mm 16 wells", - "displayCategory": "wellPlate", - "displayVolumeUnits": "µL", - "tags": [] - }, - "dimensions": { - "xDimension": 127, - "yDimension": 85, - "zDimension": 18 - }, - "wells": { - "A1": { - "depth": 11, - "totalLiquidVolume": 50, - "shape": "rectangular", - "xDimension": 15, - "yDimension": 15, - "x": 41, - "y": 65, - "z": 7 - }, - "B1": { - "depth": 11, - "totalLiquidVolume": 50, - "shape": "rectangular", - "xDimension": 15, - "yDimension": 15, - "x": 41, - "y": 50, - "z": 7 - }, - "C1": { - "depth": 11, - "totalLiquidVolume": 50, - "shape": "rectangular", - "xDimension": 15, - "yDimension": 15, - "x": 41, - "y": 35, - "z": 7 - }, - "D1": { - "depth": 11, - "totalLiquidVolume": 50, - "shape": "rectangular", - "xDimension": 15, - "yDimension": 15, - "x": 41, - "y": 20, - "z": 7 - }, - "A2": { - "depth": 11, - "totalLiquidVolume": 50, - "shape": "rectangular", - "xDimension": 15, - "yDimension": 15, - "x": 56, - "y": 65, - "z": 7 - }, - "B2": { - "depth": 11, - "totalLiquidVolume": 50, - "shape": "rectangular", - "xDimension": 15, - "yDimension": 15, - "x": 56, - "y": 50, - "z": 7 - }, - "C2": { - "depth": 11, - "totalLiquidVolume": 50, - "shape": "rectangular", - "xDimension": 15, - "yDimension": 15, - "x": 56, - "y": 35, - "z": 7 - }, - "D2": { - "depth": 11, - "totalLiquidVolume": 50, - "shape": "rectangular", - "xDimension": 15, - "yDimension": 15, - "x": 56, - "y": 20, - "z": 7 - }, - "A3": { - "depth": 11, - "totalLiquidVolume": 50, - "shape": "rectangular", - "xDimension": 15, - "yDimension": 15, - "x": 71, - "y": 65, - "z": 7 - }, - "B3": { - "depth": 11, - "totalLiquidVolume": 50, - "shape": "rectangular", - "xDimension": 15, - "yDimension": 15, - "x": 71, - "y": 50, - "z": 7 - }, - "C3": { - "depth": 11, - "totalLiquidVolume": 50, - "shape": "rectangular", - "xDimension": 15, - "yDimension": 15, - "x": 71, - "y": 35, - "z": 7 - }, - "D3": { - "depth": 11, - "totalLiquidVolume": 50, - "shape": "rectangular", - "xDimension": 15, - "yDimension": 15, - "x": 71, - "y": 20, - "z": 7 - }, - "A4": { - "depth": 11, - "totalLiquidVolume": 50, - "shape": "rectangular", - "xDimension": 15, - "yDimension": 15, - "x": 86, - "y": 65, - "z": 7 - }, - "B4": { - "depth": 11, - "totalLiquidVolume": 50, - "shape": "rectangular", - "xDimension": 15, - "yDimension": 15, - "x": 86, - "y": 50, - "z": 7 - }, - "C4": { - "depth": 11, - "totalLiquidVolume": 50, - "shape": "rectangular", - "xDimension": 15, - "yDimension": 15, - "x": 86, - "y": 35, - "z": 7 - }, - "D4": { - "depth": 11, - "totalLiquidVolume": 50, - "shape": "rectangular", - "xDimension": 15, - "yDimension": 15, - "x": 86, - "y": 20, - "z": 7 - } - }, - "groups": [ - { - "metadata": { - "wellBottomShape": "flat" - }, - "wells": [ - "A1", - "B1", - "C1", - "D1", - "A2", - "B2", - "C2", - "D2", - "A3", - "B3", - "C3", - "D3", - "A4", - "B4", - "C4", - "D4" - ] - } - ], - "parameters": { - "format": "irregular", - "quirks": [], - "isTiprack": false, - "isMagneticModuleCompatible": false, - "loadName": "petridish_90mm_16_wells" - }, - "namespace": "custom_beta", - "version": 1, - "schemaVersion": 2, - "cornerOffsetFromSlot": { - "x": 0, - "y": 0, - "z": 0 - } -} \ No newline at end of file diff --git a/assets/protocols/protocol-1-template.py b/assets/protocols/protocol-1-template.py index 2478cf3..3323404 100644 --- a/assets/protocols/protocol-1-template.py +++ b/assets/protocols/protocol-1-template.py @@ -6,7 +6,7 @@ metadata = { "apiLevel": "2.15", - "protocolName": "Protocol 1: E. coli heat shock transformation", + "protocolName": "Protocol 1: Heat shock transformation", "description": "OT-2 protocol for standard E. coli heat shock transformation using thermocycler.", "author": "Stracquadanio Lab" } @@ -27,7 +27,6 @@ ############################################## - def load_json_data(json_content: str) -> dict: """Load JSON formatted string with experiment parameters.""" return json.loads(json_content) @@ -38,33 +37,28 @@ def load_csv_data(csv_content: str): data = {key: [] for key in csv_reader.fieldnames if key} for row in csv_reader: for key, value in row.items(): - data[key].append(float(value) if 'volume' in key else value) - return namedtuple('ProtocolData', data.keys())(*[data[key] for key in data.keys()]) + data[key].append(float(value) if "volume" in key else value) + return namedtuple("ProtocolData", data.keys())(*[data[key] for key in data.keys()]) def load_or_reuse_labware(protocol: protocol_api.ProtocolContext, plate_info: Dict[str, str], loaded_plates: Dict[str, protocol_api.Labware]): """Load a plate into the protocol or reuse an existing one if the slot is already occupied.""" slot = plate_info["slot"] return loaded_plates[slot] if slot in loaded_plates else loaded_plates.setdefault(slot, protocol.load_labware(plate_info["name"], slot)) -def filter_and_transfer(pipette, sources: List[str], volumes: List[float], destinations: List[str]) -> Tuple[List[str], List[float], List[str]]: - """Filters out sources, volumes, and destinations. Adjusts wells to start with 'A' for 8-channel pipettes.""" - seen_columns, filtered_sources, filtered_volumes, filtered_destinations = set(), [], [], [] +def filter_data(pipette, sources: List[str], volumes: List[float], destinations: List[str]) -> Tuple[List[str], List[float], List[str]]: + """Filters out "NA" sources and adjusts well identifiers for 8-channel pipettes.""" + seen_columns, filtered = set(), [] is_multi_channel = "8-Channel" in str(pipette) - - for source, volume, destination in zip(sources, volumes, destinations): - destination_column = destination[1:] - formatted_destination = 'A' + destination_column if is_multi_channel else destination - formatted_source = 'A' + source[1:] if is_multi_channel else source - if formatted_destination in seen_columns: + for src, vol, dest in zip(sources, volumes, destinations): + if src == "NA" or ("A" + dest[1:] if is_multi_channel else dest) in seen_columns: continue - seen_columns.add(formatted_destination) - filtered_sources.append(formatted_source) - filtered_volumes.append(volume) - filtered_destinations.append(formatted_destination) - - return filtered_sources, filtered_volumes, filtered_destinations + formatted_dest = "A" + dest[1:] if is_multi_channel else dest + seen_columns.add(formatted_dest) + filtered.append(("A" + src[1:] if is_multi_channel else src, vol, formatted_dest)) + + return zip(*filtered) def setup_pipettes(protocol: protocol_api.ProtocolContext, pipette_info: Dict[str, Any]) -> Dict[str, protocol_api.InstrumentContext]: """Load specified pipettes into the protocol based on configuration details provided.""" @@ -80,7 +74,7 @@ def select_pipette(volume: List[float], loaded_pipettes: Dict[str, protocol_api. """ Determine the appropriate pipette based on the volume and available pipettes. """ if len(loaded_pipettes) == 1: return next(iter(loaded_pipettes.values())) - pipette_type = "p20" if min(volume, default=float('inf')) <= 20 else "p300" + pipette_type = "p20" if min(volume, default=float("inf")) <= 20 else "p300" for pipette_name, pipette in loaded_pipettes.items(): if pipette_type in pipette_name: return pipette @@ -90,8 +84,9 @@ def run(protocol: protocol_api.ProtocolContext): """Main function for running the protocol.""" json_params = load_json_data(INPUT_JSON_FILE) data = load_csv_data(INPUT_CSV_FILE) - loaded_pipettes = setup_pipettes(protocol, json_params) + protocol.set_rail_lights(True) + loaded_pipettes = setup_pipettes(protocol, json_params) pipette_cells = select_pipette(data.cells_volume, loaded_pipettes) pipette_dna = select_pipette(data.dna_volume, loaded_pipettes) pipette_media = select_pipette(data.media_volume, loaded_pipettes) @@ -101,8 +96,6 @@ def run(protocol: protocol_api.ProtocolContext): dna_plate = load_or_reuse_labware(protocol, {"name": json_params["dna_plate_name"], "slot": json_params["dna_plate_slot"]}, loaded_plates) media_plate = load_or_reuse_labware(protocol, {"name": json_params["media_plate_name"], "slot": json_params["media_plate_slot"]}, loaded_plates) - protocol.set_rail_lights(True) - if json_params["destination_plate_slot"] == "thermocycler": thermocycler_mod = protocol.load_module("thermocycler") destination_plate = thermocycler_mod.load_labware(json_params["destination_plate_name"]) @@ -113,12 +106,10 @@ def run(protocol: protocol_api.ProtocolContext): destination_plate = protocol.load_labware(json_params["destination_plate_name"], json_params["destination_plate_slot"]) ########## ADD COMPETENT CELLS ########## - protocol.comment("Adding competent cells.") + protocol.comment("Adding competent cells:") pipette_cells.pick_up_tip() mixed_wells = set() - cells_source, cells_volume, cells_destination = filter_and_transfer(pipette_cells, data.cells_well, data.cells_volume, data.destination_well) - print(data.cells_well, data.cells_volume, data.destination_well) - print(cells_source, cells_volume, cells_destination) + cells_source, cells_volume, cells_destination = filter_data(pipette_cells, data.cells_well, data.cells_volume, data.destination_well) cumulative_cell_volumes = defaultdict(float) for src_well, vol_cells in zip(cells_source, cells_volume): @@ -126,12 +117,10 @@ def run(protocol: protocol_api.ProtocolContext): for src_well, vol_cells, dest_well in zip(cells_source, cells_volume, cells_destination): if src_well not in mixed_wells: - mix_volume = cumulative_cell_volumes[src_well] - if mix_volume > pipette_cells.max_volume: - mix_volume = pipette_cells.max_volume + mix_volume = cumulative_cell_volumes[src_well] / 2 + mix_volume = mix_volume if mix_volume <= pipette_cells.max_volume / 2 else pipette_cells.max_volume pipette_cells.mix(1, mix_volume, cells_plate.wells_by_name()[src_well]) mixed_wells.add(src_well) - pipette_cells.transfer(volume=vol_cells, source=cells_plate.wells_by_name()[src_well], dest=destination_plate.wells_by_name()[dest_well], @@ -139,16 +128,17 @@ def run(protocol: protocol_api.ProtocolContext): pipette_cells.drop_tip() ########## ADD DNA ########## - protocol.comment("Adding DNA.") - dna_source, dna_volume, dna_destination = filter_and_transfer(pipette_dna, data.dna_well, data.dna_volume, data.destination_well,) + protocol.comment("Adding DNA:") + dna_source, dna_volume, dna_destination = filter_data(pipette_dna, data.dna_well, data.dna_volume, data.destination_well,) for src_well, vol_dna, dest_well, vol_cells in zip(dna_source, dna_volume, dna_destination, cells_volume): pipette_dna.pick_up_tip() pipette_dna.aspirate(volume=vol_dna, location=dna_plate.wells_by_name()[src_well]) pipette_dna.dispense(volume=vol_dna, location=destination_plate.wells_by_name()[dest_well]) - mixing_volume = (vol_dna + vol_cells) / 2 - pipette_dna.mix(repetitions=2, volume=mixing_volume, location=destination_plate.wells_by_name()[dest_well]) + mix_volume = (vol_dna + vol_cells) / 2 + mix_volume = mix_volume if mix_volume <= pipette_dna.max_volume / 2 else pipette_dna.max_volume + pipette_dna.mix(repetitions=2, volume=mix_volume, location=destination_plate.wells_by_name()[dest_well]) pipette_dna.blow_out(location=destination_plate.wells_by_name()[dest_well]) - pipette_dna.move_to(destination_plate.wells_by_name()[dest_well].bottom()) # To make sure that the droplets from the blow out do not stay on the tip + pipette_dna.move_to(destination_plate.wells_by_name()[dest_well].bottom()) # To ensure droplets from the blow out do not remain on the tip pipette_dna.drop_tip() ########## HEAT SHOCK TRANSFORMATION ########## @@ -166,19 +156,17 @@ def run(protocol: protocol_api.ProtocolContext): protocol.pause("Put plate into an external thermocycler for heat-shock transformation and return.") ######## ADD RECOVERY MEDIUM ########## - protocol.comment("Adding recovery media.") - media_source, media_volume, media_destination = filter_and_transfer(pipette_media, data.media_well, data.media_volume, data.destination_well) + protocol.comment("Adding recovery media:") + media_source, media_volume, media_destination = filter_data(pipette_media, data.media_well, data.media_volume, data.destination_well) for src_well, vol_media, dest_well, vol_cells in zip(media_source, media_volume, media_destination, cells_volume): - pipette_media.pick_up_tip() - pipette_media.aspirate(volume=vol_media + vol_cells, location=media_plate.wells_by_name()[src_well]) - pipette_media.dispense(volume=vol_media, location=destination_plate.wells_by_name()[dest_well]) - for _ in range(2): - pipette_media.aspirate(volume=(vol_media + vol_cells) / 2, location=destination_plate.wells_by_name()[dest_well]) - pipette_media.dispense(volume=(vol_media + vol_cells) / 2, location=destination_plate.wells_by_name()[dest_well]) - pipette_media.blow_out(location=destination_plate.wells_by_name()[dest_well]) - pipette_media.move_to(destination_plate.wells_by_name()[dest_well].bottom()) - pipette_media.drop_tip() - + mix_volume = (vol_media + vol_cells) / 2 + mix_volume = mix_volume if mix_volume <= pipette_media.max_volume / 2 else pipette_media.max_volume + pipette_media.transfer(volume=vol_media, + source=media_plate.wells_by_name()[src_well], + dest=destination_plate.wells_by_name()[dest_well], + mix_after=(2, mix_volume), + new_tip="always") + ######## RECOVERY INCUBATION ########## if json_params["destination_plate_slot"] == "thermocycler": thermocycler_mod.close_lid() diff --git a/assets/protocols/protocol-2-template.py b/assets/protocols/protocol-2-template.py index 46615c6..d696434 100644 --- a/assets/protocols/protocol-2-template.py +++ b/assets/protocols/protocol-2-template.py @@ -9,7 +9,7 @@ "apiLevel": "2.15", "protocolName": "Protocol 2: Colony selection", "description": "OT-2 protocol for colony selection by selective agar plate spotting.", - "author": "Martyna Kasprzyk" + "author": "Stracquadanio Lab" } ############################################## @@ -38,28 +38,24 @@ def load_csv_data(csv_content: str): data = {key: [] for key in csv_reader.fieldnames if key} for row in csv_reader: for key, value in row.items(): - data[key].append(float(value) if 'volume' in key else value) - return namedtuple('ProtocolData', data.keys())(*[data[key] for key in data.keys()]) + data[key].append(float(value) if "volume" in key else value) + return namedtuple("ProtocolData", data.keys())(*[data[key] for key in data.keys()]) -def filter_and_transfer(pipette, sources: List[str], volumes: List[float], destinations: List[str], locations: List[str]) -> Tuple[List[str], List[float], List[str], List[float]]: +def filter_data(pipette, sources: List[str], volumes: List[float], destinations: List[str], locations: List[str]) -> Tuple[List[str], List[float], List[str], List[float]]: """Filters sources, volumes, and destinations.""" - seen_columns, filtered_sources, filtered_volumes, filtered_destinations, filtered_locations = set(), [], [], [], [] + seen_columns, filtered = set(), [] is_multi_channel = "8-Channel" in str(pipette) + for source, volume, destination, location in zip(sources, volumes, destinations, locations): - if "|" in destination: - formatted_destination = destination - else: - formatted_destination = 'A' + destination[1:] if is_multi_channel else destination - if formatted_destination in seen_columns: - continue - formatted_source = 'A' + source[1:] if is_multi_channel and "|" not in source else source - seen_columns.add(formatted_destination) - filtered_sources.append(formatted_source) - filtered_volumes.append(volume) - filtered_destinations.append(formatted_destination) - filtered_locations.append(int(location)) - - return filtered_sources, filtered_volumes, filtered_destinations, filtered_locations + formatted_destination = "A" + destination[1:] if is_multi_channel else destination + destination_location_key = (formatted_destination, location) + + if destination_location_key not in seen_columns: + seen_columns.add(destination_location_key) + formatted_source = "A" + source[1:] if is_multi_channel else source + filtered.append((formatted_source, volume, formatted_destination, int(location))) + + return zip(*filtered) def agar_height(agar_plate_weight: float, empty_agar_plate_weight: float, agar_plate_area: float, agar_density: float, spotting_height: float) -> float: """Calculate the the agar height based on the base area of the plate, weight of the empty plate, the weight of plate with agar and the agar density.""" @@ -72,35 +68,35 @@ def run(protocol: protocol_api.ProtocolContext): """Main function for running the protocol.""" json_params = load_json_data(INPUT_JSON_FILE) csv_data = load_csv_data(INPUT_CSV_FILE) + protocol.set_rail_lights(True) pipette_tipracks = [protocol.load_labware(load_name=json_params["tiprack_name"], location=i) for i in json_params["tiprack_slots"]] pipette = protocol.load_instrument(instrument_name=json_params["pipette_name"], mount=json_params["pipette_mount"], tip_racks=pipette_tipracks) - - protocol.set_rail_lights(True) - source_well, spotting_volume, destination_well, locations = filter_and_transfer(pipette, csv_data.source_well, csv_data.spotting_volume, csv_data.destination_well, csv_data.agar_plate_location) - - agar_labware = {int(slot): protocol.load_labware(load_name=json_params["agar_plate_name"], location=slot, label=f"Agar Plate {i+1}") - for i, slot in enumerate(json_params["agar_plate_slot"])} - + if json_params["source_plate_slot"] == "thermocycler": - thermocycler_mod = protocol.load_module("thermocycler") # Thermocycler module, takes location 7,8,10,11 + thermocycler_mod = protocol.load_module("thermocycler") source_plate = thermocycler_mod.load_labware(json_params["source_plate_name"]) thermocycler_mod.open_lid() else: source_plate = protocol.load_labware(load_name=json_params["source_plate_name"], location=json_params["source_plate_slot"]) - - agar_info = {slot: {'empty_plate_weight': weight, 'agar_plate_weight': agar_weight} + + source_well, spotting_volume, destination_well, locations = filter_data(pipette, csv_data.source_well, csv_data.spotting_volume, csv_data.destination_well, csv_data.agar_plate_location) + agar_labware = {int(slot): protocol.load_labware(load_name=json_params["agar_plate_name"], location=slot, label=f"Agar Plate {i+1}") + for i, slot in enumerate(json_params["agar_plate_slot"])} + agar_info = {slot: {"empty_plate_weight": weight, "agar_plate_weight": agar_weight} for slot, weight, agar_weight in zip(json_params["agar_plate_slot"], json_params["empty_agar_plate_weight"], json_params["agar_plate_weight"])} + agar_plates = [agar_labware[loc] for loc in locations] - empty_plate_weight = [agar_info[loc]['empty_plate_weight'] for loc in locations if loc in agar_info] - agar_plate_weight = [agar_info[loc]['agar_plate_weight'] for loc in locations if loc in agar_info] + empty_plate_weight = [agar_info[loc]["empty_plate_weight"] for loc in locations if loc in agar_info] + agar_plate_weight = [agar_info[loc]["agar_plate_weight"] for loc in locations if loc in agar_info] + ######## SPOTTING ########## for plate, source, volume, destination, empty_weight, agar_weight in zip(agar_plates, source_well, spotting_volume, destination_well, empty_plate_weight, agar_plate_weight): pipette.pick_up_tip() pipette.well_bottom_clearance.dispense = 1 if "|" in destination: destinations = destination.split("|") - pipette.mix(repetitions=3, volume=pipette.max_volume / 2, location=source_plate[source], rate=2) + pipette.mix(repetitions=2, volume=20, location=source_plate[source], rate=2) for dest in destinations: pipette.aspirate(volume = volume + json_params["additional_volume"], location=source_plate[source], rate=2) pipette.well_bottom_clearance.dispense = agar_height(agar_weight, empty_weight, json_params["agar_plate_area"], json_params["agar_density"], json_params["spotting_height"]) @@ -108,7 +104,7 @@ def run(protocol: protocol_api.ProtocolContext): protocol.delay(seconds = 5) pipette.drop_tip() else: - pipette.mix(repetitions=3, volume=pipette.max_volume / 2, location=source_plate[source], rate=2) + pipette.mix(repetitions=3, volume=20, location=source_plate[source], rate=2) pipette.aspirate(volume=volume + json_params["additional_volume"], location=source_plate[source], rate=2) pipette.well_bottom_clearance.dispense=agar_height(agar_weight, empty_weight, json_params["agar_plate_area"], json_params["agar_density"], json_params["spotting_height"]) pipette.dispense(volume=volume, location=plate[destination], rate=4) diff --git a/assets/protocols/protocol-3-template.py b/assets/protocols/protocol-3-template.py index 44e3495..276f131 100644 --- a/assets/protocols/protocol-3-template.py +++ b/assets/protocols/protocol-3-template.py @@ -8,9 +8,9 @@ metadata = { "apiLevel": "2.15", - "protocolName": "Protocol 3 - Colony Sampling", + "protocolName": "Protocol 3: Colony Sampling", "description": "OT-2 protocol for colony sampling from agar plates.", - "author": "Martyna Kasprzyk" + "author": "Stracquadanio Lab" } ############################################## @@ -39,8 +39,8 @@ def load_csv_data(csv_content: str): data = {key: [] for key in csv_reader.fieldnames if key} for row in csv_reader: for key, value in row.items(): - data[key].append(float(value) if 'volume' in key else value) - return namedtuple('ProtocolData', data.keys())(*[data[key] for key in data.keys()]) + data[key].append(float(value) if "volume" in key else value) + return namedtuple("ProtocolData", data.keys())(*[data[key] for key in data.keys()]) def setup_pipettes(protocol: protocol_api.ProtocolContext, pipette_info: Dict[str, Any]) -> Dict[str, protocol_api.InstrumentContext]: """Load specified pipettes into the protocol based on configuration details provided.""" @@ -54,10 +54,13 @@ def setup_pipettes(protocol: protocol_api.ProtocolContext, pipette_info: Dict[st def select_pipette(loaded_pipettes: Dict[str, protocol_api.InstrumentContext], volume: List[float] = None, is_sampling: bool = False) -> protocol_api.InstrumentContext: """Determine the appropriate pipette based on volume requirements and whether it's for sampling.""" + if len(loaded_pipettes) == 1: + return next(iter(loaded_pipettes.values())) + if is_sampling: return min(loaded_pipettes.values(), key=lambda p: p.max_volume) else: - pipette_type = "p20" if min(volume, default=float('inf')) <= 20 else "p300" + pipette_type = "p20" if min(volume, default=float("inf")) <= 20 else "p300" for pipette_name, pipette in loaded_pipettes.items(): if pipette_type in pipette_name: return pipette @@ -69,8 +72,8 @@ def filter_data(pipette, sources: List[str], volumes: List[float], destinations: is_multi_channel = "8-Channel" in str(pipette) for i, (source, destination) in enumerate(zip(sources, destinations)): - formatted_destination = 'A' + destination[1:] if is_multi_channel else destination - formatted_source = 'A' + source[1:] if is_multi_channel else source + formatted_destination = "A" + destination[1:] if is_multi_channel else destination + formatted_source = "A" + source[1:] if is_multi_channel else source if formatted_destination not in seen_columns: seen_columns.add(formatted_destination) @@ -113,6 +116,7 @@ def run(protocol: protocol_api.ProtocolContext): """Main function for running the protocol.""" json_params = load_json_data(INPUT_JSON_FILE) csv_data = load_csv_data(INPUT_CSV_FILE) + protocol.set_rail_lights(True) loaded_pipettes = setup_pipettes(protocol, json_params) pipette_media = select_pipette(loaded_pipettes, csv_data.media_volume) @@ -121,26 +125,25 @@ def run(protocol: protocol_api.ProtocolContext): media_plate = protocol.load_labware(load_name = json_params["media_plate_name"], location = json_params["media_plate_slot"]) culture_plate = protocol.load_labware(load_name = json_params["destination_plate_name"], location = json_params["destination_plate_slot"]) - sampling_source_wells, sampling_destination_wells, locations = filter_data(pipette_sampling, csv_data.sampling_source_well, [], csv_data.destination_well, csv_data.agar_plate_location) - media_source_wells, media_volumes, media_destination_wells = filter_data(pipette_media, csv_data.media_source_well, csv_data.media_volume, csv_data.destination_well) + colony_wells, sampling_destination_wells, locations = filter_data(pipette_sampling, csv_data.colony_well, [], csv_data.destination_well, csv_data.agar_plate_location) + media_wells, media_volumes, media_destination_wells = filter_data(pipette_media, csv_data.media_well, csv_data.media_volume, csv_data.destination_well) + agar_labware = {int(slot): protocol.load_labware(load_name=json_params["agar_plate_name"], location=slot, label=f"Agar Plate {i+1}") for i, slot in enumerate(json_params["agar_plate_slot"])} - agar_info = {slot: {'empty_plate_weight': weight, 'agar_plate_weight': agar_weight} + agar_info = {slot: {"empty_plate_weight": weight, "agar_plate_weight": agar_weight} for slot, weight, agar_weight in zip(json_params["agar_plate_slot"], json_params["empty_agar_plate_weight"], json_params["agar_plate_weight"])} agar_plates = [agar_labware[loc] for loc in locations] - empty_plate_weight = [agar_info[loc]['empty_plate_weight'] for loc in locations if loc in agar_info] - agar_plate_weight = [agar_info[loc]['agar_plate_weight'] for loc in locations if loc in agar_info] + empty_plate_weight = [agar_info[loc]["empty_plate_weight"] for loc in locations if loc in agar_info] + agar_plate_weight = [agar_info[loc]["agar_plate_weight"] for loc in locations if loc in agar_info] - protocol.set_rail_lights(True) - ########## DISTRIBUTE MEDIA ########## pipette_media.transfer(volume=media_volumes, - source=[media_plate.wells_by_name()[well] for well in media_source_wells], + source=[media_plate.wells_by_name()[well] for well in media_wells], dest=[culture_plate.wells_by_name()[well] for well in media_destination_wells], new_tip="once") ########## SAMPLING ########## - for plate, source, destination, empty_weight, agar_weight in zip(agar_plates, sampling_source_wells, sampling_destination_wells, empty_plate_weight, agar_plate_weight): + for plate, source, destination, empty_weight, agar_weight in zip(agar_plates, colony_wells, sampling_destination_wells, empty_plate_weight, agar_plate_weight): pipette_sampling.pick_up_tip() sampling_height = agar_height(agar_weight, empty_weight, json_params["agar_plate_area"], json_params["agar_density"], json_params["agar_pierce_depth"]) colony_well = plate.wells_by_name()[source] @@ -155,7 +158,7 @@ def run(protocol: protocol_api.ProtocolContext): pipette_sampling.move_to(colony_sampling) pipette_sampling.move_to(media_plate[destination].bottom()) - pipette_sampling.mix(repetitions=2, rate=4) + pipette_sampling.mix(repetitions=2, volume=20, rate=4) pipette_sampling.drop_tip() protocol.set_rail_lights(False) \ No newline at end of file diff --git a/assets/protocols/protocol-4-template.py b/assets/protocols/protocol-4-template.py index 4525ce2..ae6bad7 100644 --- a/assets/protocols/protocol-4-template.py +++ b/assets/protocols/protocol-4-template.py @@ -5,10 +5,10 @@ from typing import Tuple, List, Dict, NamedTuple, Any, Optional metadata = { - "apiLevel": "2.13", - "protocolName": "Protocol 4 - Protein Expression Induction", - "description": "OT-2 protocol for inducing the protein expression.", - "author": "Martyna Kasprzyk", + "apiLevel": "2.15", + "protocolName": "Protocol 4: Protein Expression Induction", + "description": "OT-2 protocol for protein expression indcution.", + "author": "Stracquadanio Lab", } ############################################## @@ -38,8 +38,8 @@ def load_csv_data(csv_content: str): data = {key: [] for key in csv_reader.fieldnames if key} for row in csv_reader: for key, value in row.items(): - data[key].append(float(value) if 'volume' in key else value) - return namedtuple('ProtocolData', data.keys())(*[data[key] for key in data.keys()]) + data[key].append(float(value) if "volume" in key else value) + return namedtuple("ProtocolData", data.keys())(*[data[key] for key in data.keys()]) def load_or_reuse_labware(protocol: protocol_api.ProtocolContext, plate_info: Dict[str, str], loaded_plates: Dict[str, protocol_api.Labware]): """Load a plate into the protocol or reuse an existing one if the slot is already occupied.""" @@ -47,27 +47,17 @@ def load_or_reuse_labware(protocol: protocol_api.ProtocolContext, plate_info: Di return loaded_plates[slot] if slot in loaded_plates else loaded_plates.setdefault(slot, protocol.load_labware(plate_info["name"], slot)) def filter_data(pipette, sources: List[str], volumes: List[float], destinations: List[str]) -> Tuple[List[str], List[float], List[str]]: - """ - Filters out sources, volumes, and destinations. Adjusts wells to start with 'A' for 8-channel pipettes, unless source is "NA". - Leaves data unmodified for single-channel pipettes except for filtering duplicate destinations. - """ + """Filters out sources, volumes, and destinations. Adjusts wells to start with "A" for 8-channel pipettes, unless source is "NA". + Leaves data unmodified for single-channel pipettes.""" seen_columns, filtered_sources, filtered_volumes, filtered_destinations = set(), [], [], [] is_multi_channel = "8-Channel" in str(pipette) for source, volume, destination in zip(sources, volumes, destinations): - if source == "NA": - # formatted_source = source - pass - else: - formatted_source = 'A' + source[1:] if is_multi_channel else source - - destination_column = destination[1:] - formatted_destination = 'A' + destination_column if is_multi_channel else destination - - if formatted_destination in seen_columns: - continue - + if source == "NA" or (formatted_destination := "A" + destination[1:] if is_multi_channel else destination) in seen_columns: + continue + seen_columns.add(formatted_destination) + formatted_source = "A" + source[1:] if is_multi_channel and source != "NA" else source filtered_sources.append(formatted_source) filtered_volumes.append(volume) filtered_destinations.append(formatted_destination) @@ -88,7 +78,7 @@ def select_pipette(volume: List[float], loaded_pipettes: Dict[str, protocol_api. """ Determine the appropriate pipette based on the volume and available pipettes. """ if len(loaded_pipettes) == 1: return next(iter(loaded_pipettes.values())) - pipette_type = "p20" if min(volume, default=float('inf')) <= 20 else "p300" + pipette_type = "p20" if min(volume, default=float("inf")) <= 20 else "p300" for pipette_name, pipette in loaded_pipettes.items(): if pipette_type in pipette_name: return pipette @@ -98,6 +88,7 @@ def run(protocol: protocol_api.ProtocolContext): """Main function for running the protocol.""" json_params = load_json_data(INPUT_JSON_FILE) csv_data = load_csv_data(INPUT_CSV_FILE) + protocol.set_rail_lights(True) loaded_pipettes = setup_pipettes(protocol, json_params) pipette_media = select_pipette(csv_data.media_volume, loaded_pipettes) @@ -110,7 +101,6 @@ def run(protocol: protocol_api.ProtocolContext): inducer_plate = load_or_reuse_labware(protocol, {"name": json_params["inducer_plate_name"], "slot": json_params["inducer_plate_slot"]}, loaded_plates) destination_plate = load_or_reuse_labware(protocol, {"name": json_params["destination_plate_name"], "slot": json_params["destination_plate_slot"]}, loaded_plates) - protocol.set_rail_lights(True) ########## DISTRIBUTE MEDIA ########## media_wells, media_volumes, media_destination_wells = filter_data(pipette_media, csv_data.media_well, csv_data.media_volume, csv_data.destination_well) pipette_media.transfer(volume=media_volumes, @@ -124,10 +114,12 @@ def run(protocol: protocol_api.ProtocolContext): volume=culture_volumes, source=[culture_plate.wells_by_name()[well] for well in culture_wells], dest=[destination_plate.wells_by_name()[well] for well in culture_destination_wells], - new_tip="always", + mix_before=(2, 20), + mix_after=(1, 20), + new_tip="always" ) - protocol.pause("Incubate the culture plate with shaking untill it reaches the desired OD600 and click 'resume'.") + protocol.pause("Incubate the culture plate with shaking untill it reaches the desired growth phase and click 'resume'.") ########## INDUCER TRANSFER ########## inducer_wells, inducer_volumes, inducer_destination_wells = filter_data(pipette_inducer, csv_data.inducer_well, csv_data.inducer_volume, csv_data.destination_well) @@ -135,6 +127,7 @@ def run(protocol: protocol_api.ProtocolContext): volume=inducer_volumes, source=[inducer_plate.wells_by_name()[well] for well in inducer_wells], dest=[destination_plate.wells_by_name()[well] for well in inducer_destination_wells], + mix_after=(1, 20), new_tip="always", ) protocol.set_rail_lights(False) diff --git a/bin/create-labware.py b/bin/create-labware.py index f008990..9eacfe5 100755 --- a/bin/create-labware.py +++ b/bin/create-labware.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 - """ create_csv_labware.py @@ -16,11 +15,8 @@ import json from docopt import docopt -def create_csv_protocol_1(data_csv: str, parameters_json: str, output_csv: str) -> None: - - """ - This function creates a CSV file from CSV and JSON files of protocol 1 compatible with the labware visualisation script. - """ +def create_csv_protocol_1(data_csv, parameters_json, output_csv): + """This function creates a CSV file from CSV and JSON files of protocol 1 compatible with the labware visualisation script.""" df = pd.read_csv(data_csv) with open(parameters_json, "r") as file: plate_slots = json.load(file) @@ -36,7 +32,6 @@ def create_csv_protocol_1(data_csv: str, parameters_json: str, output_csv: str) df_id_well_volume["labware"] = plate_slots[f"{reactant}_plate_name"] df_all_reactants.append(df_id_well_volume) - # Transformation plate dataframe df_destination = pd.DataFrame({ "id": df.apply(lambda row: f'{row["dna_id"]}/{row["cells_id"]}/{row["media_id"]}', axis=1), "well_name": df["destination_well"], @@ -49,7 +44,7 @@ def create_csv_protocol_1(data_csv: str, parameters_json: str, output_csv: str) result_df = result_df.reindex(columns=["id", "location", "labware", "well_name", "volume"]) # Reorder columns result_df.to_csv(output_csv, index=False) -def create_csv_protocol_2(data_csv: str, parameters_json: str, output_csv: str) -> None: +def create_csv_protocol_2(data_csv, parameters_json, output_csv): """ This function creates a CSV file from spotting CSV and JSON files compatible with the labware visualisation script. """ @@ -57,7 +52,6 @@ def create_csv_protocol_2(data_csv: str, parameters_json: str, output_csv: str) with open(parameters_json, "r") as file: params = json.load(file) - # Create the source plate dataframe df_source_plate = pd.DataFrame({ "id": df["id"], "well_name": df["source_well"], @@ -66,18 +60,17 @@ def create_csv_protocol_2(data_csv: str, parameters_json: str, output_csv: str) "location": params["source_plate_slot"] }) - # Create the destination plate dataframe with a list of numbers for location df_destination_plate = pd.DataFrame({ "id": df["id"], "well_name": df["destination_well"], "volume": df["spotting_volume"], "labware": params["agar_plate_name"], - "location": 2 + "location": df["agar_plate_location"] }) - result_df = pd.concat([df_source_plate, df_destination_plate], ignore_index=True) # Concatenate the dataframes - result_df = result_df[["id", "location", "labware", "well_name", "volume"]] # Reorder columns for consistency - result_df.to_csv(output_csv, index=False) # Write the result to a CSV file + result_df = pd.concat([df_source_plate, df_destination_plate], ignore_index=True) + result_df = result_df[["id", "location", "labware", "well_name", "volume"]] + result_df.to_csv(output_csv, index=False) def create_csv_protocol_3(data_csv: str, parameters_json: str, output_csv: str) -> None: """ @@ -86,31 +79,40 @@ def create_csv_protocol_3(data_csv: str, parameters_json: str, output_csv: str) df = pd.read_csv(data_csv) with open(parameters_json, "r") as file: - plate_slots = json.load(file) + params = json.load(file) df_all_reactants = [] df_source_plate = pd.DataFrame({ - "id": df["id"], - "well_name": df["sampling_source_well"], + "id": df["colony_id"], + "well_name": df["colony_well"], "volume": 0, - "labware": plate_slots["agar_plate_name"], - "location": 1 + "labware": params["agar_plate_name"], + "location": df["agar_plate_location"] }) - df_all_reactants.append(df_source_plate) + df_all_reactants.append(df_source_plate) + + df_media_plate = pd.DataFrame({ + "id": df["media_id"], + "well_name": df["media_well"], + "volume": df["media_volume"], + "labware": params["media_plate_name"], + "location": params["media_plate_slot"] + }) + df_all_reactants.append(df_media_plate) df_destination_plate = pd.DataFrame({ - "id": df["id"], + "id": df.apply(lambda row: f'{row["colony_id"]}/{row["media_id"]}', axis=1), "well_name": df["destination_well"], "volume": df["media_volume"], - "labware": plate_slots["media_plate_name"], - "location": plate_slots["media_plate_slot"] + "labware": params["destination_plate_name"], + "location": params["destination_plate_slot"] }) df_all_reactants.append(df_destination_plate) - result_df = pd.concat(df_all_reactants, ignore_index=True) # Concatenate the grouped dataframes vertically - result_df = result_df.reindex(columns=["id", "location", "labware", "well_name", "volume"]) # Reorder columns - result_df.to_csv(output_csv, index=False) # write to a CSV file + result_df = pd.concat(df_all_reactants, ignore_index=True) + result_df = result_df.reindex(columns=["id", "location", "labware", "well_name", "volume"]) + result_df.to_csv(output_csv, index=False) def create_csv_protocol_4(data_csv, parameters_json, output_csv): """ @@ -122,46 +124,30 @@ def create_csv_protocol_4(data_csv, parameters_json, output_csv): with open(parameters_json, "r") as f: plate_slots = json.load(f) - reactants = [key.replace('_plate_slot', '') for key in plate_slots if '_plate_slot' in key] - df_all_reactants = [] - for reactant in reactants: + for reactant in ["culture", "media", "inducer"]: well_col = f"{reactant}_well" volume_col = f"{reactant}_volume" id_col = f"{reactant}_id" + df_id_well_volume = df.groupby(well_col).agg({volume_col: "sum", id_col: "first"}).reset_index() + df_id_well_volume.rename(columns={id_col: "id", well_col: "well_name", volume_col: "volume"}, inplace=True) + df_id_well_volume["location"] = plate_slots[f"{reactant}_plate_slot"] + df_id_well_volume["labware"] = plate_slots[f"{reactant}_plate_name"] + df_all_reactants.append(df_id_well_volume) - if well_col in df.columns and volume_col in df.columns and id_col in df.columns: - df_reactant = df.groupby(well_col).agg({volume_col: "sum", id_col: "first"}).reset_index() - df_reactant.rename(columns={id_col: "id", well_col: "well_name", volume_col: "volume"}, inplace=True) - df_reactant["location"] = plate_slots.get(f"{reactant}_plate_slot", 'Unknown') - df_reactant["labware"] = plate_slots.get(f"{reactant}_plate_name", 'Unknown') - - df = df.merge(df_reactant[['well_name', 'id']], left_on=well_col, right_on='well_name', suffixes=('', f'_{reactant}')) - df_all_reactants.append(df_reactant) - - reactant_ids = [f"{reactant}_id" for reactant in reactants if f"{reactant}_id" in df.columns] - df['combined_id'] = df[reactant_ids].apply(lambda x: '/'.join(x.dropna().astype(str)), axis=1) - - df_induction = pd.DataFrame({ - "id": df['combined_id'], + df_destination = pd.DataFrame({ + "id": df.apply(lambda row: f'{row["culture_id"]}/{row["media_id"]}/{row["inducer_id"]}', axis=1), "well_name": df["destination_well"], - "volume": df[[col for col in df.columns if "volume" in col and any(r in col for r in reactants)]].sum(axis=1), + "volume": df[["culture_volume", "media_volume", "inducer_volume"]].sum(axis=1), "labware": plate_slots["destination_plate_name"], "location": plate_slots["destination_plate_slot"] }) - df_all_reactants.append(df_induction) + df_all_reactants.append(df_destination) result_df = pd.concat(df_all_reactants, ignore_index=True) result_df = result_df.reindex(columns=["id", "location", "labware", "well_name", "volume"]) result_df.to_csv(output_csv, index=False) - - df_all_reactants.append(df_induction) - - result_df = pd.concat(df_all_reactants, ignore_index=True) # Concatenate the grouped dataframes vertically - result_df = result_df.reindex(columns=["id", "location", "labware", "well_name", "volume"]) # Reorder columns - result_df.to_csv(output_csv, index=False) # write to a CSV file - def main(): args = docopt(__doc__) @@ -173,10 +159,8 @@ def main(): create_csv_protocol_1(csv_data, json_data, csv_output) elif "2" in csv_data: create_csv_protocol_2(csv_data, json_data, csv_output) - elif "3" in csv_data: create_csv_protocol_3(csv_data, json_data, csv_output) - if "4" in csv_data: create_csv_protocol_4(csv_data, json_data, csv_output) diff --git a/main.nf b/main.nf index f8190e5..65ddbbe 100644 --- a/main.nf +++ b/main.nf @@ -12,7 +12,8 @@ workflow PROTOCOL_1 { file("$params.protocol_template_dir") ) SIMULATE_PROTOCOL_1( - MAKE_PROTOCOL_1.out + MAKE_PROTOCOL_1.out, + file("$params.opentrons_labware_dir") ) CREATE_LABWARE_CSV_1( tuple(file("$params.protocol_1_data"), file("$params.protocol_1_config")) @@ -36,7 +37,8 @@ workflow PROTOCOL_2 { file("$params.protocol_template_dir") ) SIMULATE_PROTOCOL_2( - MAKE_PROTOCOL_2.out + MAKE_PROTOCOL_2.out, + file("$params.opentrons_labware_dir") ) CREATE_LABWARE_CSV_2( tuple(file("$params.protocol_2_data"), file("$params.protocol_2_config")) @@ -62,7 +64,8 @@ workflow PROTOCOL_3 { file("$params.protocol_template_dir") ) SIMULATE_PROTOCOL_3( - MAKE_PROTOCOL_3.out + MAKE_PROTOCOL_3.out, + file("$params.opentrons_labware_dir") ) CREATE_LABWARE_CSV_3( tuple(file("$params.protocol_3_data"), file("$params.protocol_3_config")) @@ -88,7 +91,8 @@ workflow PROTOCOL_4 { file("$params.protocol_template_dir") ) SIMULATE_PROTOCOL_4( - MAKE_PROTOCOL_4.out + MAKE_PROTOCOL_4.out, + file("$params.opentrons_labware_dir") ) CREATE_LABWARE_CSV_4( tuple(file("$params.protocol_4_data"), file("$params.protocol_4_config")) diff --git a/modules/protocol_compiler/main.nf b/modules/protocol_compiler/main.nf index 85f7d65..23855e9 100644 --- a/modules/protocol_compiler/main.nf +++ b/modules/protocol_compiler/main.nf @@ -95,88 +95,92 @@ process MAKE_PROTOCOL_4 { process SIMULATE_PROTOCOL_1 { - publishDir "${params.resultsDir}", pattern: "protocol-1-instructions.txt", mode: "copy" + publishDir "${params.resultsDir}", pattern: "protocol-1-simulation.txt", mode: "copy" input: path(protocol) + path(labware) output: - path "protocol-1-instructions.txt" + path "protocol-1-simulation.txt" script: """ - opentrons_simulate ${protocol} > protocol-1-instructions.txt + opentrons_simulate ${protocol} -L ${labware} > protocol-1-simulation.txt """ stub: """ - touch protocol-1-instructions.txt + touch protocol-1-simulation.txt """ } process SIMULATE_PROTOCOL_2 { - publishDir "${params.resultsDir}", pattern: "protocol-2-instructions.txt", mode: "copy" + publishDir "${params.resultsDir}", pattern: "protocol-2-simulation.txt", mode: "copy" input: path(protocol) + path(labware) output: - path "protocol-2-instructions.txt" + path "protocol-2-simulation.txt" script: """ - opentrons_simulate ${protocol} > protocol-2-instructions.txt + opentrons_simulate ${protocol} -L ${labware} > protocol-2-simulation.txt """ stub: """ - touch protocol-2-instructions.txt + touch protocol-2-simulation.txt """ } process SIMULATE_PROTOCOL_3 { - publishDir "${params.resultsDir}", pattern: "protocol-3-instructions.txt", mode: "copy" + publishDir "${params.resultsDir}", pattern: "protocol-3-simulation.txt", mode: "copy" input: path(protocol) + path(labware) output: - path "protocol-3-instructions.txt" + path "protocol-3-simulation.txt" script: """ - opentrons_simulate ${protocol} > protocol-3-instructions.txt + opentrons_simulate ${protocol} -L ${labware} > protocol-3-simulation.txt """ stub: """ - touch protocol-3-instructions.txt + touch protocol-3-simulation.txt """ } process SIMULATE_PROTOCOL_4 { - publishDir "${params.resultsDir}", pattern: "protocol-4-instructions.txt", mode: "copy" + publishDir "${params.resultsDir}", pattern: "protocol-4-simulation.txt", mode: "copy" input: path(protocol) + path(labware) output: - path "protocol-4-instructions.txt" + path "protocol-4-simulation.txt" script: """ - opentrons_simulate ${protocol} > protocol-4-instructions.txt + opentrons_simulate ${protocol} -L ${labware} > protocol-4-simulation.txt """ stub: """ - touch protocol-4-instructions.txt + touch protocol-4-simulation.txt """ } \ No newline at end of file