/**
* Roboliq: Automation for liquid-handling robots
* @copyright 2017, ETH Zurich, Ellis Whitehead
* @license GPL-3.0
*/
/**
* Namespace for the ``transporter`` commands.
* @namespace transporter
* @version v1
*/
/**
* Transporter commands module.
* @module commands/transporter
* @return {Protocol}
* @version v1
*/
const _ = require('lodash');
import yaml from 'yamljs';
const commandHelper = require('../commandHelper.js');
const expect = require('../expect.js');
const misc = require('../misc.js');
/**
* Create predicates for objects of type = "Transporter"
* @static
*/
var objectToPredicateConverters = {
"Transporter": function(name, data) {
return [{ "isTransporter": { "equipment": name } }];
},
};
/**
* Transport a lid from a container to a destination site.
*/
function moveLidFromContainerToSite(params, parsed, data) {
// console.log("transporter.moveLidFromContainerToSite:"); console.log(JSON.stringify(parsed, null, '\t'))
if (parsed.input.containerObject.type != "Plate") {
expect.throw({paramName: "object"}, "expected lid to be on a plate; instead lid's location is "+parsed.input.container);
}
const transporterLogic = require('./transporterLogic.json');
const keys = ["null", "one"];
const movePlateParams = makeMoveLidFromContainerToSiteParams(parsed);
const shop = require('../HTN/shop.js');
const llpl = require('../HTN/llpl.js').create();
llpl.initializeDatabase(data.predicates);
let input0 = data.predicates;
let plan;
let errorLog = "";
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const method = {method: makeMoveLidFromContainerToSiteMethod(parsed, movePlateParams, i)};
input0 = input0.concat(_.values(transporterLogic[key]));
input0 = input0.concat([method]);
if (transporterLogic.hasOwnProperty(key)) {
llpl.addToDatabase(transporterLogic[key]);
}
llpl.addToDatabase([method]);
// const fs = require('fs');
// fs.writeFileSync("a.json", JSON.stringify(llpl.database, null, '\t'));
const queryResultsAll = queryMovePlateMethod(llpl, method.method, i);
// If we didn't find a path for this method:
if (queryResultsAll.length === 0) {
//const queryResultOne = llpl.query({stackable: {below: "?below", above: "ourlab.model.lidModel_384_square"}});
//console.log("queryResultOne: " +JSON.stringify(queryResultOne))
const text = debugMovePlateMethod(llpl, method.method, queryResultsAll, i);
errorLog += text;
}
// If we did find a path:
else {
// console.log(`${queryResultsAll.length} path(s) found, e.g.: ${JSON.stringify(queryResultsAll[0])}`);
const tasks = { "tasks": { "ordered": [{ moveLidFromContainerToSite: movePlateParams }] } };
const input = input0.concat([tasks]);
var planner = shop.makePlanner(input);
plan = planner.plan();
//console.log(key, plan)
if (!_.isEmpty(plan)) {
//console.log("plan found for "+key)
//console.log(planner.ppPlan(plan));
}
else {
console.log("apparently unable to open some site or something")
}
break;
}
}
if (_.isEmpty(plan)) {
console.log(errorLog);
//console.log("transporter.movePlate: "+JSON.stringify(parsed, null, '\t'))
return {errors: [`unable to find a transportation path for lid ${parsed.input.object} on ${parsed.input.container} from ${parsed.input.origin} to ${parsed.input.destination}`]};
}
var tasks = planner.listAndOrderTasks(plan, true);
//console.log("Tasks:")
//console.log(JSON.stringify(tasks, null, ' '));
var cmdList = _(tasks).map(function(task) {
return _(task).map(function(taskParams, taskName) {
return (data.planHandlers.hasOwnProperty(taskName)) ? data.planHandlers[taskName](taskParams, params, data) : [];
}).flatten().value();
}).flatten().value();
// console.log("cmdList: "+JSON.stringify(cmdList, null, ' '));
// Create the expansion object
var expansion = {};
var i = 1;
_.forEach(cmdList, function(cmd) {
expansion[i.toString()] = cmd;
i += 1;
});
// Create the effets object
var effects = {};
effects[`${parsed.objectName.object}.location`] = parsed.objectName.destination;
return {
expansion: expansion,
effects: effects
};
}
moveLidFromContainerToSite.inputSpec = {
lid: "object",
lidModel: "object*model",
container: "object*location",
containerObject: "object*location*",
model: "?object*location*model",
origin: "?object*location*location",
destination: "destination"
};
/**
* Take the parsed parameters passed to `transporter.moveLidFromContainerToSite`
* and create the parameter list for the task `moveLidFromContainerToSite` in `makeMoveLidFromContainerToSiteMethod()`.
* If any of the following parameters are not specified, then they will also
* be a part of the created parameters: agent, equipment, program
*/
function makeMoveLidFromContainerToSiteParams(parsed) {
// console.log("makeMoveLidFromContainerToSiteParams: "+JSON.stringify(parsed))
return _.pickBy({
agent: (parsed.objectName.agent) ? "?agent" : undefined,
equipment: (parsed.objectName.equipment) ? "?equipment" : undefined,
program: (parsed.objectName.program || parsed.value.program) ? "?program" : undefined,
lid: "?lid",
container: "?container",
destination: "?destination"
});
}
function makeMoveLidFromContainerToSiteMethod(parsed, moveLidParams, n) {
// console.log("makeMoveLidFromContainToSiteMethod: "+JSON.stringify(parsed, null, '\t'));
const {lid, lidModel, container, model, origin, destination} = parsed.input;
function makeArray(name, value) {
return _.map(_.range(n), i => (_.isUndefined(value)) ? name+(i+1) : value);
}
const agents = makeArray("?agent", parsed.objectName.agent);
const equipments = makeArray("?equipment", parsed.objectName.equipment);
const programs = makeArray("?program", parsed.objectName.program || parsed.value.program)
//const origin = parsed.value.object.location;
//
if (n === 0) {
const name = "moveLidFromContainerToSite-0";
return {
"description": `${name}: transport lid from container to destination in ${n} step(s)`,
"task": {"moveLidFromContainerToSite": moveLidParams},
"preconditions": [
{"location": {"labware": lid, "site": destination}}
],
"subtasks": {"ordered": [
{"print": {"text": name}}
]}
};
}
else if (n === 1) {
const name = "moveLidFromContainerToSite-1";
return {
"description": `${name}: transport plate from origin to destination in ${n} step(s)`,
"task": {"moveLidFromContainerToSite": moveLidParams},
"preconditions": [
{"model": {"labware": lid, "model": lidModel}}, // TODO: Superfluous, but maybe check anyway
{"location": {"labware": lid, "site": container}},
//{"labwareHasLid": {"labware": container}},
{"model": {"labware": container, "model": model}},
{"location": {"labware": container, "site": origin}},
{"siteIsOpen": {"site": origin}},
{"siteIsOpen": {"site": destination}},
{"siteModel": {"site": origin, "siteModel": "?originModel"}},
{"siteModel": {"site": destination, "siteModel": "?destinationModel"}},
{"stackable": {"below": "?destinationModel", "above": lidModel}},
{"siteIsClear": {"site": destination}},
{"siteCliqueSite": {"siteClique": "?siteClique1", "site": origin}},
{"siteCliqueSite": {"siteClique": "?siteClique1", "site": destination}},
{"transporter.canAgentEquipmentProgramSites": {"agent": agents[0], "equipment": equipments[0], "program": programs[0], "siteClique": "?siteClique1"}}
],
"subtasks": {"ordered": [
{"print": {"text": name}},
{"transporter._moveLidFromContainerToSite": {"agent": agents[0], "equipment": equipments[0], "program": programs[0], lid, lidModel, container, model, origin, "originModel": "?originModel", destination, "destinationModel": "?destinationModel"}}
]}
};
}
assert(false);
}
/**
* Transport a lid from an origin site to a container.
*/
function moveLidFromSiteToContainer(params, parsed, data) {
// console.log("transporter.moveLidFromSiteToContainer:"); console.log(JSON.stringify(parsed, null, '\t'));
if (parsed.input.originType != "Site") {
expect.throw({paramName: "object"}, "expected lid to be on a site; instead lid's location is "+parsed.input.origin);
}
const transporterLogic = require('./transporterLogic.json');
const keys = ["null", "one"];
const movePlateParams = makeMoveLidFromSiteToContainerParams(parsed);
const shop = require('../HTN/shop.js');
const llpl = require('../HTN/llpl.js').create();
llpl.initializeDatabase(data.predicates);
let input0 = data.predicates;
let plan;
let errorLog = "";
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const method = {method: makeMoveLidFromSiteToContainerMethod(parsed, movePlateParams, i, llpl)};
input0 = input0.concat(_.values(transporterLogic[key]));
input0 = input0.concat([method]);
if (transporterLogic.hasOwnProperty(key)) {
llpl.addToDatabase(transporterLogic[key]);
}
llpl.addToDatabase([method]);
// const fs = require('fs');
// fs.writeFileSync("a.json", JSON.stringify(llpl.database, null, '\t'));
const queryResultsAll = queryMovePlateMethod(llpl, method.method, i);
// If we didn't find a path for this method:
if (queryResultsAll.length === 0) {
//const queryResultOne = llpl.query({stackable: {below: "?below", above: "ourlab.model.lidModel_384_square"}});
//console.log("queryResultOne: " +JSON.stringify(queryResultOne))
const text = debugMovePlateMethod(llpl, method.method, queryResultsAll, i);
errorLog += text;
}
// If we did find a path:
else {
// console.log(`${queryResultsAll.length} path(s) found, e.g.: ${JSON.stringify(queryResultsAll[0])}`);
const tasks = { "tasks": { "ordered": [{ moveLidFromSiteToContainer: movePlateParams }] } };
const input = input0.concat([tasks]);
var planner = shop.makePlanner(input);
plan = planner.plan();
//console.log(key, plan)
if (!_.isEmpty(plan)) {
//console.log("plan found for "+key)
//console.log(planner.ppPlan(plan));
}
else {
console.log("apparently unable to open some site or something")
}
break;
}
}
if (_.isEmpty(plan)) {
console.log(errorLog);
const x = _.pickBy({agent: parsed.objectName.agent, equipment: parsed.objectName.equipment, program: parsed.objectName.program || parsed.value.program, model: parsed.value.object.model, origin: parsed.objectName["object.location"], destination: parsed.objectName.destination});
//console.log("transporter.movePlate: "+JSON.stringify(parsed, null, '\t'))
return {errors: ["unable to find a transportation path for lid `"+parsed.objectName.object+"` from `"+parsed.objectName.origin+"` to `"+parsed.objectName.container+"` at `"+parsed.value.container.location+"`", JSON.stringify(x)]};
}
var tasks = planner.listAndOrderTasks(plan, true);
//console.log("Tasks:")
//console.log(JSON.stringify(tasks, null, ' '));
var cmdList = _(tasks).map(function(task) {
return _(task).map(function(taskParams, taskName) {
return (data.planHandlers.hasOwnProperty(taskName)) ? data.planHandlers[taskName](taskParams, params, data) : [];
}).flatten().value();
}).flatten().value();
// console.log("cmdList: "+JSON.stringify(cmdList, null, ' '));
// Create the expansion object
var expansion = {};
var i = 1;
_.forEach(cmdList, function(cmd) {
expansion[i.toString()] = cmd;
i += 1;
});
// Create the effets object
var effects = {};
effects[`${parsed.objectName.object}.location`] = parsed.objectName.container;
// console.log("expansion: "+JSON.stringify(expansion, null, '\t'))
// console.log("effects: "+JSON.stringify(effects, null, '\t'))
return {
expansion: expansion,
effects: effects
};
}
moveLidFromSiteToContainer.inputSpec = {
origin: "object*location",
originType: "object*location*type",
lid: "object",
lidModel: "object*model",
container: "container",
model: "container*model",
destination: "container*location"
};
/**
* Take the parsed parameters passed to `transporter.moveLidFromSiteToContainer`
* and create the parameter list for the task `moveLidFromSiteToContainer` in `makeMoveLidFromSiteToContainerMethod()`.
* If any of the following parameters are not specified, then they will also
* be a part of the created parameters: agent, equipment, program
*/
function makeMoveLidFromSiteToContainerParams(parsed) {
// console.log("makeMoveLidFromSiteToContainerParams: "+JSON.stringify(parsed))
return _.pickBy({
agent: (parsed.objectName.agent) ? "?agent" : undefined,
equipment: (parsed.objectName.equipment) ? "?equipment" : undefined,
program: (parsed.objectName.program || parsed.value.program) ? "?program" : undefined,
lid: "?lid",
origin: "?origin",
container: "?container"
});
}
function makeMoveLidFromSiteToContainerMethod(parsed, moveLidParams, n, llpl) {
// console.log("makeMoveLidFromContainToSiteMethod: "+JSON.stringify(parsed, null, '\t'));
const {origin, lid, lidModel, container, model, destination} = parsed.input;
// console.log({lid, lidModel, container, model, origin, destination})
const originQuery = llpl.query({"siteModel": {"site": origin, "siteModel": "?originModel"}});
const destinationQuery = llpl.query({"siteModel": {"site": destination, "siteModel": "?destinationModel"}});
// console.log("originQuery: "+JSON.stringify(originQuery, null, '\t'))
// console.log("destinationQuery: "+JSON.stringify(destinationQuery, null, '\t'))
const originModel = originQuery[0].siteModel.siteModel;
const destinationModel = destinationQuery[0].siteModel.siteModel;
// console.log("labwareHasNoLid?: "+JSON.stringify(llpl.query({"labwareHasNoLid": {"site": container}})))
function makeArray(name, value) {
return _.map(_.range(n), i => (_.isUndefined(value)) ? name+(i+1) : value);
}
const agents = makeArray("?agent", parsed.objectName.agent);
const equipments = makeArray("?equipment", parsed.objectName.equipment);
const programs = makeArray("?program", parsed.objectName.program || parsed.value.program)
if (n === 0) {
const name = "moveLidFromSiteToContainer-0";
return {
"description": `${name}: transport lid from container to destination in ${n} step(s)`,
"task": {"moveLidFromSiteToContainer": moveLidParams},
"preconditions": [
{"location": {"labware": lid, "labware": destination}}
],
"subtasks": {"ordered": [
{"print": {"text": name}}
]}
};
}
else if (n === 1) {
const name = "moveLidFromSiteToContainer-1";
return {
"description": `${name}: transport plate from origin to destination in ${n} step(s)`,
"task": {"moveLidFromSiteToContainer": moveLidParams},
"preconditions": [
// {"model": {"labware": lid, "model": lidModel}}, // TODO: Superfluous, but maybe check anyway
{"location": {"labware": lid, "site": origin}},
{"model": {"labware": container, "model": model}},
{"location": {"labware": container, "site": destination}},
{"siteIsOpen": {"site": origin}},
{"siteIsOpen": {"site": destination}},
{"siteModel": {"site": origin, "siteModel": originModel}},
{"siteModel": {"site": destination, "siteModel": destinationModel}},
{"stackable": {"below": model, "above": lidModel}},
{"labwareHasNoLid": {"labware": container}},
{"siteCliqueSite": {"siteClique": "?siteClique1", "site": origin}},
{"siteCliqueSite": {"siteClique": "?siteClique1", "site": destination}},
{"transporter.canAgentEquipmentProgramSites": {"agent": agents[0], "equipment": equipments[0], "program": programs[0], "siteClique": "?siteClique1"}}
],
"subtasks": {"ordered": [
{"print": {"text": name}},
{"transporter._moveLidFromSiteToContainer": {"agent": agents[0], "equipment": equipments[0], "program": programs[0], lid, lidModel, container, model, origin, "originModel": originModel, destination, "destinationModel": destinationModel}}
]}
};
}
assert(false);
}
function makeMovePlateParams(parsed) {
return _.merge({}, {
agent: (parsed.objectName.agent) ? "?agent" : undefined,
equipment: (parsed.objectName.equipment) ? "?equipment" : undefined,
program: (parsed.objectName.program || parsed.value.program) ? "?program" : undefined,
labware: "?labware",
destination: "?destination"
});
}
function makeMovePlateMethod(parsed, movePlateParams, n) {
//console.log("makeMovePlateMethod: "+JSON.stringify(parsed, null, '\t'));
function makeArray(name, value) {
return _.map(_.range(n), i => (_.isUndefined(value)) ? name+(i+1) : value);
}
const labware = parsed.objectName.object;
const model = parsed.value.object.model;
const origin = parsed.value.object.location;
const destination = parsed.objectName.destination;
const agents = makeArray("?agent", parsed.objectName.agent);
const equipments = makeArray("?equipment", parsed.objectName.equipment);
const programs = makeArray("?program", parsed.objectName.program || parsed.value.program)
//const origin = parsed.value.object.location;
//
if (n === 0) {
const name = "movePlate-0";
return {
"description": `${name}: transport plate from origin to destination in ${n} step(s)`,
"task": {"movePlate": movePlateParams},
"preconditions": [
{"location": {"labware": labware, "site": destination}}
],
"subtasks": {"ordered": [
{"print": {"text": name}}
]}
};
}
else if (n === 1) {
const name = "movePlate-1";
return {
"description": `${name}: transport plate from origin to destination in ${n} step(s)`,
"task": {"movePlate": movePlateParams},
"preconditions": [
{"model": {"labware": labware, "model": model}}, // TODO: Superfluous, but maybe check anyway
{"location": {"labware": labware, "site": origin}}, // TODO: Superfluous, but maybe check anyway
{"siteModel": {"site": origin, "siteModel": "?originModel"}},
{"siteModel": {"site": destination, "siteModel": "?destinationModel"}},
{"stackable": {"below": "?destinationModel", "above": model}},
{"siteIsClear": {"site": destination}},
{"siteCliqueSite": {"siteClique": "?siteClique1", "site": origin}},
{"siteCliqueSite": {"siteClique": "?siteClique1", "site": destination}},
{"transporter.canAgentEquipmentProgramSites": {"agent": agents[0], "equipment": equipments[0], "program": programs[0], "siteClique": "?siteClique1"}}
],
"subtasks": {"ordered": [
{"print": {"text": name}},
{"openAndMovePlate": {"agent": agents[0], "equipment": equipments[0], "program": programs[0], "labware": labware, "model": model, "origin": origin, "originModel": "?originModel", "destination": destination, "destinationModel": "?destinationModel"}}
]}
};
}
else if (n === 2) {
const name = "movePlate-2";
return {
"description": `${name}: transport plate from origin to destination in ${n} step(s)`,
"task": {"movePlate": movePlateParams},
"preconditions": [
{"model": {"labware": labware, "model": model}}, // TODO: can handle this in programatically
{"location": {"labware": labware, "site": origin}}, // TODO: can handle this in programatically
{"siteModel": {"site": origin, "siteModel": "?originModel"}},
{"siteModel": {"site": destination, "siteModel": "?destinationModel"}},
{"stackable": {"below": "?destinationModel", "above": model}},
{"siteIsClear": {"site": destination}}, // TODO: Check this programmatically instead of via logic
{"siteCliqueSite": {"siteClique": "?siteClique1", "site": origin}},
{"siteCliqueSite": {"siteClique": "?siteClique2", "site": destination}},
{"siteCliqueSite": {"siteClique": "?siteClique1", "site": "?site2"}},
{"siteCliqueSite": {"siteClique": "?siteClique2", "site": "?site2"}},
{"not": {"same": {"thing1": "?site2", "thing2": origin}}},
{"not": {"same": {"thing1": "?site2", "thing2": destination}}},
{"transporter.canAgentEquipmentProgramSites": {"agent": agents[0], "equipment": equipments[0], "program": programs[0], "siteClique": "?siteClique1"}},
{"transporter.canAgentEquipmentProgramSites": {"agent": agents[1], "equipment": equipments[1], "program": programs[1], "siteClique": "?siteClique2"}},
{"siteModel": {"site": "?site2", "siteModel": "?site2Model"}},
{"stackable": {"below": "?site2Model", "above": model}},
{"siteIsClear": {"site": "?site2"}}
],
"subtasks": {"ordered": [
{"print": {"text": name}},
{"openAndMovePlate": {"agent": agents[0], "equipment": equipments[0], "program": programs[0], "labware": labware, "model": model, "origin": origin, "originModel": "?originModel", "destination": "?site2", "destinationModel": "?site2Model"}},
{"openAndMovePlate": {"agent": agents[1], "equipment": equipments[1], "program": programs[1], "labware": labware, "model": model, "origin": "?site2", "originModel": "?site2Model", "destination": destination, "destinationModel": "?destinationModel"}}
]}
};
}
else if (n === 3) {
const name = "movePlate-3";
return {
"description": `${name}: transport plate from origin to destination in ${n} step(s)`,
"task": {"movePlate": movePlateParams},
"preconditions": [
{"model": {"labware": labware, "model": model}}, // TODO: can handle this in programatically
{"location": {"labware": labware, "site": origin}}, // TODO: can handle this in programatically
{"siteModel": {"site": origin, "siteModel": "?originModel"}},
{"siteModel": {"site": destination, "siteModel": "?destinationModel"}},
{"stackable": {"below": "?destinationModel", "above": model}},
{"siteIsClear": {"site": destination}}, // TODO: Check this programmatically instead of via logic
{"siteCliqueSite": {"siteClique": "?siteClique1", "site": origin}},
{"siteCliqueSite": {"siteClique": "?siteClique3", "site": destination}},
{"siteCliqueSite": {"siteClique": "?siteClique1", "site": "?site2"}},
{"siteCliqueSite": {"siteClique": "?siteClique2", "site": "?site2"}},
{"siteCliqueSite": {"siteClique": "?siteClique2", "site": "?site3"}},
{"siteCliqueSite": {"siteClique": "?siteClique3", "site": "?site3"}},
{"not": {"same": {"thing1": "?site2", "thing2": origin}}},
{"not": {"same": {"thing1": "?site2", "thing2": destination}}},
{"not": {"same": {"thing1": "?site2", "thing2": "?site3"}}},
{"not": {"same": {"thing1": "?site3", "thing2": origin}}},
{"not": {"same": {"thing1": "?site3", "thing2": destination}}},
{"transporter.canAgentEquipmentProgramSites": {"agent": agents[0], "equipment": equipments[0], "program": programs[0], "siteClique": "?siteClique1"}},
{"transporter.canAgentEquipmentProgramSites": {"agent": agents[1], "equipment": equipments[1], "program": programs[1], "siteClique": "?siteClique2"}},
{"transporter.canAgentEquipmentProgramSites": {"agent": agents[2], "equipment": equipments[2], "program": programs[2], "siteClique": "?siteClique3"}},
{"siteModel": {"site": "?site2", "siteModel": "?site2Model"}},
{"siteModel": {"site": "?site3", "siteModel": "?site3Model"}},
{"stackable": {"below": "?site2Model", "above": model}},
{"stackable": {"below": "?site3Model", "above": model}},
{"siteIsClear": {"site": "?site2"}},
{"siteIsClear": {"site": "?site3"}}
],
"subtasks": {"ordered": [
{"print": {"text": name}},
{"openAndMovePlate": {"agent": agents[0], "equipment": equipments[0], "program": programs[0], "labware": labware, "model": model, "origin": origin, "originModel": "?originModel", "destination": "?site2", "destinationModel": "?site2Model"}},
{"openAndMovePlate": {"agent": agents[1], "equipment": equipments[1], "program": programs[1], "labware": labware, "model": model, "origin": "?site2", "originModel": "?site2Model", "destination": "?site3", "destinationModel": "?site3Model"}},
{"openAndMovePlate": {"agent": agents[2], "equipment": equipments[2], "program": programs[2], "labware": labware, "model": model, "origin": "?site3", "originModel": "?site3Model", "destination": destination, "destinationModel": "?destinationModel"}}
]}
};
}
assert(false);
}
function queryMovePlateMethod(llpl, method, n) {
//console.log("originId: "+originId)
const criteria = method.preconditions;
const queryAll = {"and": criteria};
const queryResultsAll = llpl.query(queryAll);
return queryResultsAll;
}
function debugMovePlateMethod(llpl, method, queryResultsAll, n) {
const lines = [];
const criteria = method.preconditions;
//console.log(queryResultsAll.length);
if (queryResultsAll.length === 0) {
lines.push(`\nmovePlate-${n} failed:`);
// console.log("debug: "+criteria);
// let failures = 0;
_.forEach(criteria, criterion => {
// console.log({criterion})
const queryOne = {"and": [criterion]};
const queryResultOne = llpl.query(queryOne);
//console.log("queryResultOne: "+JSON.stringify(queryResultOne));
if (queryResultOne.length === 0) {
// failures++;
lines.push("FAILED: "+JSON.stringify(criterion));
}
else {
//console.log("queryResults:\n"+JSON.stringify(queryResultOne, null, '\t'));
}
});
}
else {
console.log("found paths: "+queryResultsAll)
}
return lines.join("\n");
}
/**
* Handlers for {@link transporter} commands.
* @static
*/
var commandHandlers = {
/**
* Transport a lid from labware to site or from site to labware.
*
* Handler should return `effects` with the lid's new location
* and set or remove labware's `hasLid` property.
*/
"transporter._moveLidFromContainerToSite": function(params, parsed, data) {
return {effects: {
//[`${parsed.objectName.container}.hasLid`]: false,
[`${parsed.objectName.object}.location`]: parsed.objectName.destination
}};
},
/**
* Transport a lid from labware to site or from site to labware.
*
* Handler should return `effects` with the lid's new location
* and set or remove labware's `hasLid` property.
*/
"transporter._moveLidFromSiteToContainer": function(params, parsed, data) {
return {effects: {
//[`${parsed.objectName.container}.hasLid`]: false,
[`${parsed.objectName.object}.location`]: parsed.objectName.container
}};
},
/**
* Transport a plate to a destination.
*
* Handler should return `effects` with the plate's new location.
*/
"transporter._movePlate": function(params, parsed, data) {
return {effects: {
[`${parsed.objectName.object}.location`]: parsed.objectName.destination
}};
},
"transporter.moveLidFromContainerToSite": moveLidFromContainerToSite,
"transporter.moveLidFromSiteToContainer": moveLidFromSiteToContainer,
/**
* Transport a plate to a destination.
*/
"transporter.movePlate": function(params, parsed, data) {
//console.log("transporter.movePlate("+JSON.stringify(params)+")")
const transporterLogic = require('./transporterLogic.json');
const keys = ["null", "one", "two", "three"];
const movePlateParams = makeMovePlateParams(parsed);
const shop = require('../HTN/shop.js');
const llpl = require('../HTN/llpl.js').create();
llpl.initializeDatabase(data.predicates);
let input0 = data.predicates;
let plan;
let errorLog = "";
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const method = {method: makeMovePlateMethod(parsed, movePlateParams, i)};
input0 = input0.concat(_.values(transporterLogic[key]));
input0 = input0.concat([method]);
if (transporterLogic.hasOwnProperty(key)) {
llpl.addToDatabase(transporterLogic[key]);
}
llpl.addToDatabase([method]);
// const fs = require('fs');
// fs.writeFileSync("a.json", JSON.stringify(llpl.database, null, '\t'));
const queryResultsAll = queryMovePlateMethod(llpl, method.method, i);
// If we didn't find a path for this method:
if (queryResultsAll.length === 0) {
const text = debugMovePlateMethod(llpl, method.method, queryResultsAll, i);
errorLog += text;
}
// If we did find a path:
else {
// console.log(`${queryResultsAll.length} path(s) found, e.g.: ${JSON.stringify(queryResultsAll[0])}`);
const tasks = { "tasks": { "ordered": [{ movePlate: movePlateParams }] } };
const input = input0.concat([tasks]);
var planner = shop.makePlanner(input);
plan = planner.plan();
//console.log(key, plan)
if (!_.isEmpty(plan)) {
//console.log("plan found for "+key)
//console.log(planner.ppPlan(plan));
}
else {
console.log("apparently unable to open some site or something")
}
break;
}
}
/*
const transporterPredicates = _(transporterLogic).values().map(x => _.values(x)).flatten().value();
var input0 = [].concat(data.predicates, transporterPredicates, [tasksOrdered]);
var input = input0;
//console.log(JSON.stringify(input, null, '\t'));
var shop = require('../HTN/shop.js');
var planner = shop.makePlanner(input);
var plan = planner.plan();
//console.log("plan:\n"+JSON.stringify(plan, null, ' '));
var x = planner.ppPlan(plan);
console.log(x);
*/
if (_.isEmpty(plan)) {
console.log(errorLog);
/*
var agentId = params.agent || "?agent";
var modelId = parsed.value.object.model || "?model";
var originId = parsed.value.object.location || "?site";
debug_movePlate_null(input0, agentId, parsed.objectName.object, modelId, originId, parsed.objectName.destination);
debug_movePlate_one(input0, agentId, parsed.objectName.object, modelId, originId, parsed.objectName.destination);
for (let i = 0; i <= 3; i++) {
const method = makeMovePlateMethod(parsed, movePlateParams, i);
debugMovePlateMethod()
*/
}
if (_.isEmpty(plan)) {
const x = _.merge({}, {agent: parsed.objectName.agent, equipment: parsed.objectName.equipment, program: parsed.objectName.program || parsed.value.program, model: parsed.value.object.model, origin: parsed.value.object.location, destination: parsed.objectName.destination});
//console.log("transporter.movePlate: "+JSON.stringify(parsed, null, '\t'))
return {errors: ["unable to find a transportation path for `"+parsed.objectName.object+"` from `"+misc.findObjectsValue(parsed.objectName.object+".location", data.objects)+"` to `"+parsed.objectName.destination+"`", JSON.stringify(x)]};
}
var tasks = planner.listAndOrderTasks(plan, true);
// console.log("Tasks:")
// console.log(JSON.stringify(tasks, null, ' '));
var cmdList = _(tasks).map(function(task) {
return _(task).map(function(taskParams, taskName) {
return (data.planHandlers.hasOwnProperty(taskName)) ? data.planHandlers[taskName](taskParams, params, data) : [];
}).flatten().value();
}).flatten().value();
// console.log("cmdList:")
// console.log(JSON.stringify(cmdList, null, ' '));
// Create the expansion object
var expansion = {};
var i = 1;
_.forEach(cmdList, function(cmd) {
expansion[i.toString()] = cmd;
i += 1;
});
// console.log({expansion})
// Create the effets object
var effects = {};
effects[`${parsed.objectName.object}.location`] = parsed.objectName.destination;
return {
expansion: expansion,
effects: effects
};
},
"transporter.doThenRestoreLocation": function(params, parsed, data) {
//console.log("transporter.doThenRestoreLocation("+JSON.stringify(parsed, null, '\t')+")");
const expansion = _.cloneDeep(_.values(parsed.value.steps));
// console.log("objects: "+JSON.stringify(parsed.value.objects))
for (let i = 0; i < parsed.value.objects.length; i++) {
const labwareName = parsed.objectName[`objects.${i}`];
const command = _.merge({}, {
command: "transporter.movePlate",
agent: parsed.objectName.agent,
equipment: parsed.objectName.equipment,
program: parsed.value.program,
object: labwareName,
destination: parsed.value.objects[i].location
});
expansion.push(command);
}
return { expansion };
}
};
/**
* Plan handler to allow other modules to use `transporter._movePlate` as a
* planning action.
* @static
*/
var planHandlers = {
"transporter._movePlate": function(params, parentParams, data) {
return [{
command: "transporter._movePlate",
agent: params.agent,
equipment: params.equipment,
program: params.program,
object: params.labware,
destination: params.destination
}];
},
"transporter._moveLidFromContainerToSite": function(params, parentParams, data) {
return [{
command: "transporter._moveLidFromContainerToSite",
agent: params.agent,
equipment: params.equipment,
program: params.program,
object: params.lid,
container: params.container,
destination: params.destination
}];
},
"transporter._moveLidFromSiteToContainer": function(params, parentParams, data) {
return [{
command: "transporter._moveLidFromSiteToContainer",
agent: params.agent,
equipment: params.equipment,
program: params.program,
object: params.lid,
origin: params.origin,
container: params.container
}];
},
};
module.exports = {
roboliq: "v1",
objectToPredicateConverters: objectToPredicateConverters,
schemas: yaml.load(__dirname+'/../schemas/transporter.yaml'),
commandHandlers: commandHandlers,
planHandlers: planHandlers
};