/**
* Roboliq: Automation for liquid-handling robots
* @copyright 2017, ETH Zurich, Ellis Whitehead
* @license GPL-3.0
*/
/**
* Incubator commands module (see {@tutorial Commands#incubator} or [command specification](tutorial-Commands.html#incubator)).
*
* See {@link roboliq#Protocol}.
* @module commands/incubator
* @return {Protocol}
* @version v1
*/
var _ = require('lodash');
var jmespath = require('jmespath');
import yaml from 'yamljs';
var commandHelper = require('../commandHelper.js');
var expect = require('../expect.js');
var misc = require('../misc.js');
/**
* Create predicates for objects of type = "Incubator"
* @static
*/
var objectToPredicateConverters = {
"Incubator": function(name, object) {
return [{ "isIncubator": { "equipment": name } }];
},
};
/*
function closeAll(parsed, data, effects) {
// Close equipment
effects[parsed.objectName.equipment+".open"] = false;
// Indicate that all internal sites are closed
_.forEach(parsed.value.equipment.sitesInternal, function(site) { effects[site+".closed"] = true; });
}
*/
/**
* Handlers for {@link incubator} commands.
* @static
*/
var commandHandlers = {
"incubator.incubatePlates": function(params, parsed, data) {
var llpl = require('../HTN/llpl.js').create();
llpl.initializeDatabase(data.predicates);
//console.log(JSON.stringify(parsed, null, '\t'))
var agent = parsed.objectName.agent || "?agent";
var equipment = parsed.objectName.equipment || "?equipment";
var object1 = parsed.value.object1;
var object2 = parsed.value.object2;
if (object1.model != object2.model)
return {errors: ["object1 and object2 must have the same model for centrifugation."]};
var query0 = {
"incubator.canAgentEquipmentModelSite1Site2": {
"agent": "?agent",
"equipment": "?equipment",
"model": "?model",
"site1": "?site1",
"site2": "?site2"
}
};
var query = _.merge({}, query0,
{"incubator.canAgentEquipmentModelSite1Site2": {
"agent": parsed.objectName.agent,
"equipment": parsed.objectName.equipment,
"model": object1.model,
"site1": parsed.objectName.site1,
"site2": parsed.objectName.site2
}}
);
var resultList = llpl.query(query);
var alternatives = jmespath.search(resultList, '[]."incubator.canAgentEquipmentModelSite1Site2"');
if (_.isEmpty(resultList)) {
var resultList2 = llpl.query(query0);
if (_.isEmpty(resultList2)) {
return {
errors: ["missing equipment data (please add predicates `incubator.canAgentEquipmentModelSite1Site`)"]
};
} else {
return {
errors: ["missing equipment configuration for " + JSON.stringify(query)]
};
}
}
// Find any parameters which can only take one specific value
var params2 = alternatives[0];
//console.log("alternatives[0]:\n"+JSON.stringify(params2))
const destination1
= (parsed.value.destinationAfter1 === "stay") ? params2.site1
: _.isUndefined(parsed.objectName.destinationAfter1) ? object1.location
: parsed.objectName.destinationAfter1;
const destination2
= (parsed.value.destinationAfter2 === "stay") ? params2.site2
: _.isUndefined(parsed.objectName.destinationAfter2) ? object2.location
: parsed.objectName.destinationAfter2;
var expansion = [
(object1.location === params2.site1) ? null : [
{
command: "equipment.openSite",
agent: params2.agent,
equipment: params2.equipment,
site: params2.site1
},
{
"command": "transporter.movePlate",
"object": parsed.objectName.object1,
"destination": params2.site1
}
],
(object2.location === params2.site2) ? null : [
{
command: "equipment.openSite",
agent: params2.agent,
equipment: params2.equipment,
site: params2.site2
},
{
"command": "transporter.movePlate",
"object": parsed.objectName.object2,
"destination": params2.site2
}
],
{
command: ["equipment.run", params2.agent, params2.equipment].join('|'),
agent: params2.agent,
equipment: params2.equipment,
program: parsed.objectName.program || parsed.value.program
},
// Move object1 back
(destination1 === params2.site1) ? null : [
{
command: "equipment.openSite",
agent: params2.agent,
equipment: params2.equipment,
site: params2.site1
},
{
"command": "transporter.movePlate",
"object": parsed.objectName.object1,
"destination": destination1
}
],
// Move object2 back
(destination2 === params2.site2) ? null : [
{
command: "equipment.openSite",
agent: params2.agent,
equipment: params2.equipment,
site: params2.site2
},
{
"command": "transporter.movePlate",
"object": parsed.objectName.object2,
"destination": destination2
}
],
// Close the incubator
(destination1 === params2.site1 && destination2 === params2.site2) ? null : {
command: "equipment.close",
agent: params2.agent,
equipment: params2.equipment
},
];
//console.log("incubator2 expansion:")
//console.log(JSON.stringify(expansion, null, '\t'))
return {
expansion: expansion,
alternatives: alternatives
};
},
"incubator.insertPlates": function(params, parsed, data) {
var llpl = require('../HTN/llpl.js').create();
llpl.initializeDatabase(data.predicates);
if (!parsed.value.object1 && !parsed.value.object2) {
// do nothing
return {};
}
var agent = parsed.objectName.agent || "?agent";
var equipment = parsed.objectName.equipment || "?equipment";
var object1 = parsed.value.object1;
var object2 = parsed.value.object2;
if (object1 && object2 && object1.model !== object2.model)
return {errors: ["object1 and object2 must have the same model for centrifugation."]};
const model = (object1) ? object1.model : object2.model;
expect.truthy({}, model, "object1 or object2 must have a `model` value");
var query0 = {
"incubator.canAgentEquipmentModelSite1Site2": {
"agent": "?agent",
"equipment": "?equipment",
"model": "?model",
"site1": "?site1",
"site2": "?site2"
}
};
var query = _.merge({}, query0,
{"incubator.canAgentEquipmentModelSite1Site2": {
"agent": parsed.objectName.agent,
"equipment": parsed.objectName.equipment,
"model": model,
"site1": parsed.objectName.site1,
"site2": parsed.objectName.site2
}}
);
var resultList = llpl.query(query);
var alternatives = jmespath.search(resultList, '[]."incubator.canAgentEquipmentModelSite1Site2"');
if (_.isEmpty(resultList)) {
var resultList2 = llpl.query(query0);
if (_.isEmpty(resultList2)) {
return {
errors: ["missing equipment data (please add predicates `incubator.canAgentEquipmentModelSite1Site`)"]
};
} else {
return {
errors: ["missing equipment configuration for " + JSON.stringify(query)]
};
}
}
// Find any parameters which can only take one specific value
var params2 = alternatives[0];
//console.log("alternatives[0]:\n"+JSON.stringify(params2))
var expansion = [
(!object1 || object1.location === params2.site1) ? null : [
{
command: "equipment.openSite",
agent: params2.agent,
equipment: params2.equipment,
site: params2.site1
},
{
"command": "transporter.movePlate",
"object": parsed.objectName.object1,
"destination": params2.site1
}
],
(!object2 || object2.location === params2.site2) ? null : [
{
command: "equipment.openSite",
agent: params2.agent,
equipment: params2.equipment,
site: params2.site2
},
{
"command": "transporter.movePlate",
"object": parsed.objectName.object2,
"destination": params2.site2
}
],
];
return {
expansion: expansion,
alternatives: alternatives
};
},
"incubator.run": function(params, parsed, data) {
var llpl = require('../HTN/llpl.js').create();
llpl.initializeDatabase(data.predicates);
//console.log(JSON.stringify(parsed, null, '\t'))
var agent = parsed.objectName.agent || "?agent";
var equipment = parsed.objectName.equipment || "?equipment";
var object1 = parsed.value.object1;
var object2 = parsed.value.object2;
if (object1.model != object2.model)
return {errors: ["object1 and object2 must have the same model for centrifugation."]};
var query0 = {
"incubator.canAgentEquipment": {
"agent": "?agent",
"equipment": "?equipment"
}
};
var query = _.merge({}, query0,
{"incubator.canAgentEquipment": {
"agent": parsed.objectName.agent,
"equipment": parsed.objectName.equipment
}}
);
var resultList = llpl.query(query);
var alternatives = jmespath.search(resultList, '[]."incubator.canAgentEquipment"');
if (_.isEmpty(resultList)) {
var resultList2 = llpl.query(query0);
if (_.isEmpty(resultList2)) {
return {
errors: ["missing equipment data (please add predicates `incubator.canAgentEquipment`)"]
};
} else {
return {
errors: ["missing equipment configuration for " + JSON.stringify(query)]
};
}
}
// Find any parameters which can only take one specific value
var params2 = alternatives[0];
//console.log("alternatives[0]:\n"+JSON.stringify(params2))
var expansion = [
{
command: ["equipment.run", params2.agent, params2.equipment].join('|'),
agent: params2.agent,
equipment: params2.equipment,
program: parsed.objectName.program || parsed.value.program
},
];
//console.log("incubator2 expansion:")
//console.log(JSON.stringify(expansion, null, '\t'))
return {
expansion: expansion,
alternatives: alternatives
};
},
};
module.exports = {
roboliq: "v1",
objectToPredicateConverters,
schemas: yaml.load(__dirname+"/../schemas/incubator.yaml"),
commandHandlers
};