Skip to content

Commit 06572e2

Browse files
author
Jan Červený
committed
NEW script Luminostat + modifications
1 parent 4c1d131 commit 06572e2

3 files changed

Lines changed: 212 additions & 153 deletions

File tree

LL-Luminostat.js

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* Luminostat regulator
3+
*
4+
* @script Lights - Luminostat
5+
* @author CzechGlobe - Department of Adaptive Biotechnologies (JaCe)
6+
* @version 0.1
7+
* @modified 16.2.2017 (JaCe)
8+
*
9+
* @notes For proper function of the script a pump has to be set to ID 4
10+
*
11+
* @param {number} pHmin Min pH/lower bound for pH stat (base) activation
12+
*
13+
* @return Flow of external/additional pump
14+
*
15+
*/
16+
17+
// static parameters
18+
var odMin = 0.5
19+
var odMax = 1.23
20+
var lightMin = 400
21+
var lightMax = lightMin * (1 + (odMax - odMin) / odMin)
22+
var expMult = 281.9177
23+
var expExpo = 1.016269
24+
25+
importPackage(java.util)
26+
importPackage(java.lang)
27+
importPackage(Packages.psi.bioreactor.core.protocol)
28+
29+
function round(number, decimals) {
30+
// Rounding specific decimal point number
31+
return +(Math.round(number + 'e+' + decimals) + 'e-' + decimals)
32+
}
33+
34+
function controlLight(odValue) {
35+
// Check for OD noise/overshots and do primitive OD averaging
36+
if (theAccessory.context().getInt('odNoise', 1)) {
37+
theAccessory.context().put('odNoise', 0)
38+
theAccessory.context().put('odLast', odValue)
39+
return null
40+
}
41+
if (Math.abs(1 - odValue / odLast) < 0.04) {
42+
odValue = (odValue + odLast) / 2
43+
theAccessory.context().put('odLast', odValue)
44+
if (odValue > odMax) {
45+
result = Math.min(expMult * Math.exp(expExpo * odValue), theAccessory.getMax());
46+
} else if (odValue > odMin) {
47+
result = Math.min(lightMin + (lightMax - lightMin) * (odValue - odMin) / (odMax - odMin), theAccessory.getMax());
48+
} else {
49+
result = theAccessory.getValue();
50+
}
51+
} else {
52+
theAccessory.context().put('odNoise', 1)
53+
theAccessory.context().put('odLast', odValue)
54+
return null
55+
}
56+
}
57+
58+
// dynamic parameters
59+
var odSensor = theGroup.getAccessory("od-sensors.od-680") // query OD accessory by key
60+
var odValue = odSensor.getValue()
61+
var odLast = theAccessory.context().getDouble('odLast', 0.0)
62+
63+
if (!isNaN(odValue) && (round(odValue, 3) !== round(odLast, 3))) {
64+
controlLight(odValue)
65+
}

PP-GrowthOptimizer.js

Lines changed: 133 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -4,73 +4,71 @@ var UserDefinedProtocol = {
44
turbidostatODMax: 0.425,
55
turbidostatODType: 720,
66
ODReadoutInterval: 60,
7-
// -optimizer parameters
8-
controlledParameter: 'none',
9-
controlledParameterSteps: [[ 1100, 25 ], [ 440, 25 ], [ 55, 25 ]],
7+
// -peristaltic pump settings
8+
peristalticPumpID: 5,
9+
peristalticPumpSpeed: 100,
10+
peristalticPumpSlowDownRange: 25,
11+
peristalticPumpSlowDownFactor: 75,
1012
// -optimizer stability check
1113
growthStatistics: true,
1214
regressionODType: 680,
13-
stabilizationTimeMin: 8,
14-
stabilizationTimeMax: 24,
15-
growthRateEvalFrac: 2 / 3,
1615
analyzedSteps: 6,
1716
intervalOfConfidenceMax: 3.0,
1817
growthTrendMax: 1.5,
19-
// -peristaltic pump settings
20-
peristalticPumpID: 5,
21-
peristalticPumpSpeed: 100,
22-
peristalticPumpSlowDownRange: 25,
23-
peristalticPumpSlowDownFactor: 75,
24-
// -advanced options
18+
stabilizationTimeMin: 8,
19+
stabilizationTimeMax: 24,
2520
growthRateEvalDelay: 420,
21+
growthRateEvalFrac: 2 / 3,
22+
// -optimizer parameters
23+
controlledParameter: 'none',
24+
controlledParameterSteps: [[ 1100, 25 ], [ 440, 25 ], [ 55, 25 ]],
2625
groupGMS: theGroup
2726
}
2827

29-
/* globals
30-
importPackage, java, Packages, theGroup, theAccessory, theExperiment, theLogger, ProtoConfig, ETrendFunction, result:true
31-
*/
28+
/* global importPackage, java, Packages, theGroup, theAccessory, theExperiment, theLogger, ProtoConfig, ETrendFunction, result:true */
3229

3330
/**
34-
* OD Regulator Using External/Additional Pump
35-
*
36-
* @script Peristaltic Pump - Automatic Growth Characterization
37-
* @author CzechGlobe - Department of Adaptive Biotechnologies (JaCe)
38-
* @version 3.1.3
39-
* @modified 24.4.2018 (JaCe)
40-
*
41-
* @notes For proper functionality of the script "OD Regulator" protocol has to be disabled as well as chosen
42-
* controlled accessory protocols (i.e. Lights, Thermoregulation, GMS, Stirrer).
43-
* The controlled pump has to be set to ID 5 to allow compatibility with other scripts
44-
*
45-
* @param {number} turbidostatODMin [AU] - Minimum OD/lower bound for OD regulator/turbidostat
46-
* @param {number} turbidostatODMax [AU] - Maximum OD/upper bound for OD regulator/turbidostat
47-
* @param {number} turbidostatODType [680/720/735] - OD sensor used for turbidostat control
48-
* @param {number} ODReadoutInterval [s] - Defines how often is the OD measured
49-
* @param {number} peristalticPumpSpeed [%] - Nominal pump speed used for dilution of the suspension
50-
* @param {number} peristalticPumpSlowDownRange [%] - Lower range where the pump slows down
51-
* @param {number} peristalticPumpSlowDownFactor [%] - Slow down factor for the pump
52-
* @param {number} growthStatistics [true/false] - Enable or disable calculation of growth statistics. Note that the doubling time (Dt) calculation also includes information about the fit coefficient of determination (CoD in %), known as R-squared
53-
* @param {number} regressionODType [680/720/735] - OD sensor used for doubling time determination
54-
* @param {number} analyzedSteps [-] - Number of steps to be analyzed for stability check
55-
* @param {number} intervalOfConfidenceMax [%] - Maximum allowed percents of 95% Confidence Interval
56-
* @param {number} growthTrendMax [%] - Maximum growth speed trend in time
57-
* @param {number} stabilizationTimeMin [h] - Minimum duration of each characterization step
58-
* @param {number} stabilizationTimeMax [h] - Maximum duration of each characterization step
59-
* @param {number} growthRateEvalDelay [s] - Time after dilution where data for doubling time determination are ignored. By default growthRateEvalFrac, i.e. only limited fraction of the data points is used for calculations.
60-
* @param {number} growthRateEvalFrac [0-1] - Defines whether to use particular fraction of the data points for doubling time determination.
61-
* This is to prevent influence of post dilution effect on doubling time evaluation. If 0 or false, growthRateEvalDelay is used instead. Note that to completely disable data limitation you need to set both growthRateEvalFrac and growthRateEvalDelay to 0.
62-
* @param {string} controlledParameter ['none'/'temperature'/'lights'/'GMS'/'stirrer'/'ODRange'] - Supported parameters to control by the script
63-
* @param {array} controlledParameterSteps - List of values for the controlled parameter. Examples:
64-
* temperature = [ 28, 32, 34, 30, 26, 22 ]; // [oC]
65-
* lights = [[ 55, 25 ],[ 110, 25 ],[ 220, 25 ],[ 440, 25 ],[ 880,25 ]]; // [uE]
66-
* GMS = [[ 195.88, 5.873 ],[ 195.88, 12.478 ],[ 185.30, 18.257 ],[ 185.30,25.274 ]]; // [ml/min]
67-
* stirrer = [ 30, 50, 65, 80, 95 ]; // [%] !!! works only with SW version 0.7.14 and later
68-
* ODRange = [[0.4, 0.425], [0.2, 0.215], [0.1, 0.113]]; // [AU]
69-
* @param {string} groupGMS - Identifies the group that contains Gas Mixing System.
70-
*
71-
* @return Flow of external/additional pump
72-
*
73-
*/
31+
* OD Regulator Using External/Additional Pump
32+
*
33+
* @script Peristaltic Pump - Automatic Growth Characterization
34+
* @author CzechGlobe - Department of Adaptive Biotechnologies (JaCe)
35+
* @version 3.1.3
36+
* @modified 24.4.2018 (JaCe)
37+
*
38+
* @notes For proper functionality of the script "OD Regulator" protocol has to be disabled as well as chosen
39+
* controlled accessory protocols (i.e. Lights, Thermoregulation, GMS, Stirrer).
40+
* The controlled pump has to be set to ID 5 to allow compatibility with other scripts
41+
*
42+
* @param {number} turbidostatODMin [AU] - Minimum OD/lower bound for OD regulator/turbidostat
43+
* @param {number} turbidostatODMax [AU] - Maximum OD/upper bound for OD regulator/turbidostat
44+
* @param {number} turbidostatODType [680/720/735] - OD sensor used for turbidostat control
45+
* @param {number} ODReadoutInterval [s] - Defines how often is the OD measured
46+
* @param {number} peristalticPumpID [3-7] - Defines peristaltic pump ID set to the pump used for fresh media supply (quasi-continuous mode)
47+
* @param {number} peristalticPumpSpeed [%] - Nominal pump speed used for dilution of the suspension
48+
* @param {number} peristalticPumpSlowDownRange [%] - Lower range where the pump slows down
49+
* @param {number} peristalticPumpSlowDownFactor [%] - Slow down factor for the pump
50+
* @param {number} growthStatistics [true/false] - Enable or disable calculation of growth statistics. Note that the doubling time (Dt) calculation also includes information about the fit coefficient of determination (CoD in %), known as R-squared
51+
* @param {number} regressionODType [680/720/735] - OD sensor used for doubling time determination
52+
* @param {number} analyzedSteps [-] - Number of steps to be analyzed for stability check
53+
* @param {number} intervalOfConfidenceMax [%] - Maximum allowed percents of 95% Confidence Interval
54+
* @param {number} growthTrendMax [%] - Maximum growth speed trend in time
55+
* @param {number} stabilizationTimeMin [h] - Minimum duration of each characterization step
56+
* @param {number} stabilizationTimeMax [h] - Maximum duration of each characterization step
57+
* @param {number} growthRateEvalDelay [s] - Time after dilution where data for doubling time determination are ignored. By default growthRateEvalFrac, i.e. only limited fraction of the data points is used for calculations.
58+
* @param {number} growthRateEvalFrac [0-1] - Defines whether to use particular fraction of the data points for doubling time determination.
59+
* This is to prevent influence of post dilution effect on doubling time evaluation. If 0 or false, growthRateEvalDelay is used instead. Note that to completely disable data limitation you need to set both growthRateEvalFrac and growthRateEvalDelay to 0.
60+
* @param {string} controlledParameter ['none'/'temperature'/'lights'/'GMS'/'stirrer'/'ODRange'] - Supported parameters to control by the script
61+
* @param {array} controlledParameterSteps - List of values for the controlled parameter. Examples:
62+
* temperature = [ 28, 32, 34, 30, 26, 22 ]; // [oC]
63+
* lights = [[ 55, 25 ],[ 110, 25 ],[ 220, 25 ],[ 440, 25 ],[ 880,25 ]]; // [uE]
64+
* GMS = [[ 195.88, 5.873 ],[ 195.88, 12.478 ],[ 185.30, 18.257 ],[ 185.30,25.274 ]]; // [ml/min]
65+
* stirrer = [ 30, 50, 65, 80, 95 ]; // [%] !!! works only with SW version 0.7.14 and later
66+
* ODRange = [[0.4, 0.425], [0.2, 0.215], [0.1, 0.113]]; // [AU]
67+
* @param {string} groupGMS - Identifies the group that contains Gas Mixing System.
68+
*
69+
* @return Flow of external/additional pump
70+
*
71+
*/
7472

7573
// Libraries import
7674
importPackage(java.util)
@@ -97,44 +95,44 @@ function controlParameter (parameter, values) {
9795
}
9896
var unit
9997
switch (parameter) {
100-
case 'lights':
101-
var light0 = theGroup.getAccessory('actinic-lights.light-Red')
102-
var light1 = theGroup.getAccessory('actinic-lights.light-Blue')
103-
unit = ' uE'
104-
light0.setRunningProtoConfig(new ProtoConfig(Number(values[0]))) // Red
105-
light1.setRunningProtoConfig(new ProtoConfig(Number(values[1]))) // Blue
106-
debugLogger('Lights changed.')
107-
break
108-
case 'temperature':
109-
var thermoreg = theGroup.getAccessory('thermo.thermo-reg')
110-
unit = String.fromCharCode(176) + 'C'
111-
thermoreg.setRunningProtoConfig(new ProtoConfig(Number(values)))
112-
debugLogger('Temperature changed.')
113-
break
114-
case 'GMS':
115-
var valve0 = UserDefinedProtocol.groupGMS.getAccessory('gas-mixer.valve-0-reg') // CO2
116-
var valve1 = UserDefinedProtocol.groupGMS.getAccessory('gas-mixer.valve-1-reg') // Air
117-
unit = ' ml/min'
118-
valve0.setRunningProtoConfig(new ProtoConfig(Number(values[0])))
119-
valve1.setRunningProtoConfig(new ProtoConfig(Number(values[1])))
120-
var flowAir = valve0.getProtoConfigValue()
121-
var flowCO2 = valve1.getProtoConfigValue()
122-
debugLogger('GMS settings changed. Gas Mixing set to Air flow ' + round(flowAir, 2) + ' ml/min and CO2 flow ' + round(flowCO2, 2) + ' ml/min (' + round((flowCO2 / (flowCO2 + flowAir) + 400 / 1e6) * 100, 1) + '%)')
123-
break
124-
case 'stirrer':
125-
var stirrer = theGroup.getAccessory('pwm.stirrer')
126-
unit = '%'
127-
stirrer.setRunningProtoConfig(new ProtoConfig(Number(values)))
128-
debugLogger('Stirrer changed.')
129-
break
130-
case 'ODRange':
131-
theAccessory.context().put('odMinModifier', Number(values[0]) / UserDefinedProtocol.turbidostatODMin)
132-
theAccessory.context().put('odMaxModifier', Number(values[1]) / UserDefinedProtocol.turbidostatODMax)
133-
unit = ' AU'
134-
debugLogger('Turbidostat OD range changed.')
135-
break
136-
default:
137-
return null
98+
case 'lights':
99+
var light0 = theGroup.getAccessory('actinic-lights.light-Red')
100+
var light1 = theGroup.getAccessory('actinic-lights.light-Blue')
101+
unit = ' uE'
102+
light0.setRunningProtoConfig(new ProtoConfig(Number(values[0]))) // Red
103+
light1.setRunningProtoConfig(new ProtoConfig(Number(values[1]))) // Blue
104+
debugLogger('Lights changed.')
105+
break
106+
case 'temperature':
107+
var thermoreg = theGroup.getAccessory('thermo.thermo-reg')
108+
unit = String.fromCharCode(176) + 'C'
109+
thermoreg.setRunningProtoConfig(new ProtoConfig(Number(values)))
110+
debugLogger('Temperature changed.')
111+
break
112+
case 'GMS':
113+
var valve0 = UserDefinedProtocol.groupGMS.getAccessory('gas-mixer.valve-0-reg') // CO2
114+
var valve1 = UserDefinedProtocol.groupGMS.getAccessory('gas-mixer.valve-1-reg') // Air
115+
unit = ' ml/min'
116+
valve0.setRunningProtoConfig(new ProtoConfig(Number(values[0])))
117+
valve1.setRunningProtoConfig(new ProtoConfig(Number(values[1])))
118+
var flowAir = valve0.getProtoConfigValue()
119+
var flowCO2 = valve1.getProtoConfigValue()
120+
debugLogger('GMS settings changed. Gas Mixing set to Air flow ' + round(flowAir, 2) + ' ml/min and CO2 flow ' + round(flowCO2, 2) + ' ml/min (' + round((flowCO2 / (flowCO2 + flowAir) + 400 / 1e6) * 100, 1) + '%)')
121+
break
122+
case 'stirrer':
123+
var stirrer = theGroup.getAccessory('pwm.stirrer')
124+
unit = '%'
125+
stirrer.setRunningProtoConfig(new ProtoConfig(Number(values)))
126+
debugLogger('Stirrer changed.')
127+
break
128+
case 'ODRange':
129+
theAccessory.context().put('odMinModifier', Number(values[0]) / UserDefinedProtocol.turbidostatODMin)
130+
theAccessory.context().put('odMaxModifier', Number(values[1]) / UserDefinedProtocol.turbidostatODMax)
131+
unit = ' AU'
132+
debugLogger('Turbidostat OD range changed.')
133+
break
134+
default:
135+
return null
138136
}
139137
theAccessory.context().put('controlledParameterText', parameter + ' ' + (Array.isArray(values) ? values.join(' and ') : values) + unit)
140138
theExperiment.addEvent(parameter[0].toUpperCase() + parameter.slice(1) + ' changed to ' + (Array.isArray(values) ? values.join(' and ') : values) + unit)
@@ -143,38 +141,36 @@ function controlParameter (parameter, values) {
143141
if (!theAccessory.context().getInt('initialization', 0)) {
144142
theAccessory.context().clear()
145143
switch (UserDefinedProtocol.controlledParameter) {
146-
case 'lights':
147-
if (theGroup.getAccessory('actinic-lights.light-Red').getProtoConfigValue()) {
148-
theExperiment.addEvent('!!! Disable red light protocol')
149-
}
150-
if (theGroup.getAccessory('actinic-lights.light-Blue').getProtoConfigValue()) {
151-
theExperiment.addEvent('!!! Disable red light protocol')
152-
}
153-
break
154-
case 'temperature':
155-
if (theGroup.getAccessory('thermo.thermo-reg').getProtoConfigValue()) {
156-
theExperiment.addEvent('!!! Disable thermoregulator protocol')
157-
}
158-
break
159-
case 'GMS':
160-
if (UserDefinedProtocol.groupGMS.getAccessory('gas-mixer.valve-0-reg').getProtoConfigValue()) {
161-
theExperiment.addEvent('!!! Disable GMS CO2 protocol')
162-
}
163-
if (UserDefinedProtocol.groupGMS.getAccessory('gas-mixer.valve-1-reg').getProtoConfigValue()) {
164-
theExperiment.addEvent('!!! Disable GMS Air/N2 protocol')
165-
}
166-
break
167-
case 'stirrer':
168-
if (theGroup.getAccessory('pwm.stirrer').getProtoConfigValue()) {
169-
theExperiment.addEvent('!!! Disable stirrer protocol')
170-
}
171-
break
172-
case 'ODRange':
173-
break
174-
case 'none':
175-
break
176-
default:
177-
theExperiment.addEvent('!!! Unknown parameter set for control - check controlledParameter setting')
144+
case 'lights':
145+
if (theGroup.getAccessory('actinic-lights.light-Red').getProtoConfigValue()) {
146+
theExperiment.addEvent('!!! Disable red light protocol')
147+
}
148+
if (theGroup.getAccessory('actinic-lights.light-Blue').getProtoConfigValue()) {
149+
theExperiment.addEvent('!!! Disable red light protocol')
150+
}
151+
break
152+
case 'temperature':
153+
if (theGroup.getAccessory('thermo.thermo-reg').getProtoConfigValue()) {
154+
theExperiment.addEvent('!!! Disable thermoregulator protocol')
155+
}
156+
break
157+
case 'GMS':
158+
if (UserDefinedProtocol.groupGMS.getAccessory('gas-mixer.valve-0-reg').getProtoConfigValue()) {
159+
theExperiment.addEvent('!!! Disable GMS CO2 protocol')
160+
}
161+
if (UserDefinedProtocol.groupGMS.getAccessory('gas-mixer.valve-1-reg').getProtoConfigValue()) {
162+
theExperiment.addEvent('!!! Disable GMS Air/N2 protocol')
163+
}
164+
break
165+
case 'stirrer':
166+
if (theGroup.getAccessory('pwm.stirrer').getProtoConfigValue()) {
167+
theExperiment.addEvent('!!! Disable stirrer protocol')
168+
}
169+
break
170+
case 'none':
171+
break
172+
default:
173+
theExperiment.addEvent('!!! Unknown parameter set for control - check controlledParameter setting')
178174
}
179175
// TODO rewrite following part
180176
if (UserDefinedProtocol.turbidostatODType === 720 || 735) {
@@ -256,18 +252,18 @@ function controlPump () {
256252
// setODSensorString("regression");
257253
var odSensorString, odSensorRegressionString
258254
switch (UserDefinedProtocol.turbidostatODType) {
259-
case 680:
260-
odSensorString = 'od-sensors.od-680'
261-
break
262-
default:
263-
odSensorString = theAccessory.context().get('OD7XYString', 'od-sensors.od-720')
255+
case 680:
256+
odSensorString = 'od-sensors.od-680'
257+
break
258+
default:
259+
odSensorString = theAccessory.context().get('OD7XYString', 'od-sensors.od-720')
264260
}
265261
switch (UserDefinedProtocol.regressionODType) {
266-
case 680:
267-
odSensorRegressionString = 'od-sensors.od-680'
268-
break
269-
default:
270-
odSensorRegressionString = theAccessory.context().get('RegOD7XYString', 'od-sensors.od-720')
262+
case 680:
263+
odSensorRegressionString = 'od-sensors.od-680'
264+
break
265+
default:
266+
odSensorRegressionString = theAccessory.context().get('RegOD7XYString', 'od-sensors.od-720')
271267
}
272268
var odSensor = theGroup.getAccessory(odSensorString)
273269
var odSensorRegression = theGroup.getAccessory(odSensorRegressionString)
@@ -279,7 +275,7 @@ function controlPump () {
279275
var odNoise = theAccessory.context().getInt('odNoise', 1)
280276
var odMinModifier = theAccessory.context().getDouble('odMinModifier', 1.0)
281277
var odMaxModifier = theAccessory.context().getDouble('odMaxModifier', 1.0)
282-
// Check for OD noise/overshots and primitive OD averaging
278+
// Check for OD noise/overshots and do primitive OD averaging
283279
if (!isNaN(odValue) && (round(odValue, 3) !== round(odLast, 3))) {
284280
if (odNoise) {
285281
theAccessory.context().put('odNoise', 0)
@@ -336,6 +332,7 @@ function controlPump () {
336332
var stepDoublingTimeSD = 0
337333
var stepDoublingTimeIC95 = 0
338334
var stepTrend = 0
335+
var stepCoD = 0
339336
var sumXY = 0
340337
var sumX = 0
341338
var sumY = 0

0 commit comments

Comments
 (0)