-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathexampleScript.R
160 lines (128 loc) · 5.22 KB
/
exampleScript.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
################################################################################
# Example Script for generating Worklists using R w/ rrobot #
# - as an example we generate a worklists that tries to add media to each #
# well of a 96 well plate to achieve equal OD #
# usage: #
# Rscript.exe [params] pathToReaderXML #
################################################################################
logString <- paste("Log | mkgwl_setup.R", format(Sys.time()), " ")
cat(stringr::str_pad(logString, 79, side = "right", "-"), "\n")
# install rrobot library if necessary
if (!("rrobot" %in% installed.packages())) {
install.packages("remotes")
remotes::install_github("dcangst/rrobot")
}
# load libraries
library(rrobot)
library(here)
# load parameter
parse_args("pathToReaderXML", arg_types = NULL)
volCulture <- 100
volMax <- 250
################################################################################
# Juggle data #
################################################################################
pathToReaderXML <- here("ODexample.xml")
odValues <- readInfiniteXML(pathToReaderXML)$data
# fake ODs for the purposes of this script
odValues$OD595 <- sample(c(rnorm(94, 0.4, 0.05), rnorm(2, 0.04, 0.001)), 96)
pipettingData <- odValues %>%
# discard wells with low or no growth (defined as OD595 < 0.1)
filter(OD595 > 0.1) %>%
# calculate volume to be added (rounded to microliters)
mutate(
volAdd = round((OD595 / min(OD595) - 1) * volCulture),
ODnew = OD595 * volCulture / (volCulture + volAdd))
# discard wells that can't be diluted enough in the available volume
cat("discarding wells: ")
pipettingData %>%
filter(volCulture + volAdd > volMax) %>%
print(n = Inf)
pipettingData <- pipettingData %>%
filter(volCulture + volAdd <= volMax) %>%
# add tip number used for the well (trivial, but less so for 384 well plates, needed below)
mutate(tip = as.integer(as.factor(row)))
# we want to flush tips after 6 dispense steps (i.e. do the whole plate in two
# sections). add this to pipetting data
nMultiDispense <- 6
pipettingData <- pipettingData %>%
arrange(col, row) %>%
group_by(row) %>%
mutate(
pipGroup = rep(1:ceiling(n() / nMultiDispense), each = nMultiDispense, length.out = n()),
) %>%
group_by(pipGroup) %>%
group_split()
################################################################################
# make worklist to add volumes #
################################################################################
# initialize worklist with reasonable defaults
init(filename = "exampleWorklist", LiquidClass = "Minimal FD trough")
# add a comment. These will be visible in EvoWare at runtime
adv_gwl_comment(paste0("Equalizing OD..."))
# write pipetting commands
pipGroups <- seq_along(pipettingData)
for (iGroup in pipGroups){
tipVolumes <- pipettingData[[iGroup]] %>%
group_by(tip) %>%
summarise(
nWells = length(tip),
volume = sum(volAdd + 20),
.groups = "drop"
)
if (!all(tipVolumes$volume < 800)) {
rlang::abort("volume too high")
}
# generate the tip mask (boolean vector, 0 = tip not used, 1 = tip used) and the volume mask (volume in ul)
masks <- generateMasks(tipVolumes$tip, tipVolumes$volume)
# time to aspirate!
# well aspirate from a 100ml trough at grid 29 site 1, predefined in gwl$worktable as 'trough100_mid'. Troughs have
# 1 column and 8 rows, so the well numbers are trivial (== 1:8) for other labware see helper function rc_to_well
wellsAspirate <- 1:8 * masks$tip_mask
# aspirate media
adv_aspirate(
tipMask = masks$tip_mask,
volumes = masks$vol_mask + 20, # aspirate additional 20ul to put right back, helps with droplets
RackLabel = "trough100_mid",
wellSelection = wellsAspirate,
liquidClass = "Minimal FD trough", # could leave this out because we set a default
ncol = 1, nrow = 8)
# return 20ul
adv_dispense(
tipMask = masks$tip_mask,
volumes = 20,
RackLabel = "trough100_mid",
wellSelection = wellsAspirate,
liquidClass = "Minimal FD trough",
ncol = 1, nrow = 8)
# dispense in columns of plate at grid 40 site 1, predefined in gwl$worktable as 'MP3pos_mid'.
for (icol in sort(unique(pipettingData[[iGroup]]$col))) {
# figure out volumes
tipVolumeCol <- pipettingData[[iGroup]] %>%
filter(col == icol) %>%
group_by(tip) %>%
summarise(
n_wells = length(tip),
volume = volAdd,
well = well,
.groups = "drop")
# make masks
masksCol <- generateMasks(tipVolumeCol$tip, tipVolumeCol$volume)
# write dispense command
adv_dispense(
tipMask = masksCol$tip_mask,
volumes = c(masksCol$vol_mask, 4),
RackLabel = "MP3pos_mid",
wellSelection = tipVolumeCol$well,
ncol = 12, nrow = 8)
}
if (iGroup != last(pipGroups)) {
# wash in between groups
sterile_wash()
}
}
write.gwl(gwl)
cat(stringr::str_pad(paste0(logString, "end "), 79, side = "right", "-"),
"\n\n")
# checks:
gwlToHTML("exampleWorklist.gwl")