/** * Methods for assigning which source well to use when a source liquid is * available in multiple wells. * * Details: * Assign source well by group for items without assigned source wells; if multiple syringes need to access the same source, and that source has multiple wells, then possible methods include: * * - pick first one * - rotate through source wells in order * - rotate through source wells in order of max volume * - try a simple geometrical assignment considering whether there are more tips or wells; if that fails, use previous method * - same as above, but if wells > tips, try starting at first (wells - tips) wells and see which one produces the greatest minimum final volume * * @module */ var _ = require('lodash'); var assert = require('assert'); var math = require('mathjs'); import commandHelper from '../../commandHelper.js'; var expect = require('../../expect.js'); var pipetterUtils = require('./pipetterUtils.js'); var WellContents = require('../../WellContents.js'); /** * Pick the first well in a source set and ignore the others. * * The 'sourceWell' property of each item in 'group' will be set. * * @static * @param {array} group Array of pipetting items that are grouped together * @param {object} data Data passed to the commandHandler */ function sourceMethod1(group, data) { _.forEach(group, function (item) { var source = item.source; var sourceInfo = sourceParser.parse(item.source); if (sourceInfo.source) { var wells = expect.objectsValue({}, source+".wells", data.objects); assert(!_.isEmpty(wells)); item.sourceWell = wells[0]; } else { item.sourceWell = source; } }); } // Rotate through source wells in order /*function sourceMethod2(group, data) { var sourceToWellIndex = {}; _.forEach(group, function (item) { var source = item.source; var sourceInfo = sourceParser.parse(item.source); if (sourceInfo.source) { var wells = getObjectsValue(source+".wells", data.objects); assert(!_.isEmpty(wells)); var i = (sourceToWellIndex.hasOwnProperty(source)) ? sourceToWellIndex[source] : 0; item.sourceWell = wells[i]; sourceToWellIndex[source] = (i + 1) % wells.length; } else { item.sourceWell = source; } }); }*/ /** * Rotate through source wells in order of max volume. * The 'sourceWell' property of each item in 'group' will be set. * * @static * @param {array} group Array of pipetting items that are grouped together * @param {object} data Data passed to the commandHandler * @param {object} effects (Optional) Map from variable to effects */ function sourceMethod3(group, data, effects) { // Make our own copy of the the effects object var effects = (effects) ? _.cloneDeep(effects) : {}; // Consider each source in the group separately var sourceToItems = _.groupBy(_.filter(group, x => x.source), 'source'); //console.log("sourceToItems:\n"+JSON.stringify(sourceToItems, null, ' ')); for (const items of _.values(sourceToItems)) { // console.log("sourceMethod3", items) assert(items[0].source); var wells = _.clone(items[0].source); assert(!_.isEmpty(wells)); for (const item of items) { //console.log("wells: ", wells); if (_.isArray(wells)) { if (wells.length === 1) { item.source = wells[0]; } else { var wellAndVolumes = _.map(wells, function(wellName) { var volume = WellContents.getWellVolume(wellName, data, effects); return {wellName, volume: volume.toNumber('ul')}; }); // Sort by volume //console.log({wellAndVolumes}) math.sort(wellAndVolumes, function(a, b) { return -math.compare(a.volume, b.volume)}); // Pick well with greatest volume var wellName = wellAndVolumes[0].wellName; item.source = wellName; //console.log("well chosen:", wellName); // Move the chosen well to the back of the array _.pull(wells, wellName); wells.push(wellName); const params = {items: [_.clone(item)]}; params.items[0].volume = item.volume.format({precision: 14}); const schema = { properties: { items: { description: "Data about what should be pipetted where", "type": "array", items: {type: "pipetter._PipetteItem"} } }, required: ["items"] }; //console.log("param of items:") //console.log(JSON.stringify(params, null, '\t')) const parsed = commandHelper.parseParams(params, data, schema); //console.log("parsed:"); //console.log(JSON.stringify(parsed, null, '\t')) // Get effect of pipetting, so that source volumes are changed appropriately var effects2 = pipetterUtils.getEffects_pipette(parsed, data, effects); _.merge(effects, effects2); //console.log("effects2", effects2) //console.log("effects", effects) } } else { //item.source = item.source; } } } } module.exports = { sourceMethod1, //sourceMethod2: sourceMethod2, sourceMethod3 }