extensions/net.sf.basedb.meludi/trunk/resources/libprep/pools.js

Code
Comments
Other
Rev Date Author Line
3449 28 Jul 15 olle 1
3449 28 Jul 15 olle 2 var POOL_NAMES = 
3449 28 Jul 15 olle 3   ['i', 'ii', 'iii', 'iv', 'v', 'vi', 'vii', 'viii', 'ix', 'x', 'xi', 'xii' ];
3449 28 Jul 15 olle 4
3449 28 Jul 15 olle 5 BC_1_8 =   ['AD001', 'AD002', 'AD003', 'AD004', 'AD005', 'AD006', 'AD007', 'AD008'];
3449 28 Jul 15 olle 6 BC_8_1 =   ['AD008', 'AD007', 'AD006', 'AD005', 'AD004', 'AD003', 'AD002', 'AD001'];
3449 28 Jul 15 olle 7 BC_9_16 =  ['AD009', 'AD010', 'AD011', 'AD012', 'AD013', 'AD014', 'AD015', 'AD016'];
3449 28 Jul 15 olle 8 BC_16_9 =  ['AD016', 'AD015', 'AD014', 'AD013', 'AD012', 'AD011', 'AD010', 'AD009'];
3449 28 Jul 15 olle 9 BC_18_27 = ['AD018', 'AD019', 'AD020', 'AD021', 'AD022', 'AD023', 'AD025', 'AD027'];
3449 28 Jul 15 olle 10 BC_27_18 = ['AD027', 'AD025', 'AD023', 'AD022', 'AD021', 'AD020', 'AD019', 'AD018'];
3449 28 Jul 15 olle 11
3449 28 Jul 15 olle 12 // Index Sets = IS
3449 28 Jul 15 olle 13 var IS_G1 = {color: 'bg-green',  barcodes: BC_1_8};
3449 28 Jul 15 olle 14 var IS_G2 = {color: 'bg-green',  barcodes: BC_9_16};
3449 28 Jul 15 olle 15 var IS_G3 = {color: 'bg-green',  barcodes: BC_18_27};
3449 28 Jul 15 olle 16
3449 28 Jul 15 olle 17 var IS_G4 = {color: 'bg-green-dk',  barcodes: BC_8_1};
3449 28 Jul 15 olle 18 var IS_G5 = {color: 'bg-green-dk',  barcodes: BC_16_9};
3449 28 Jul 15 olle 19 var IS_G6 = {color: 'bg-green-dk',  barcodes: BC_27_18};
3449 28 Jul 15 olle 20
3449 28 Jul 15 olle 21 var IS_B1 = {color: 'bg-blue',   barcodes: BC_1_8};
3449 28 Jul 15 olle 22 var IS_B2 = {color: 'bg-blue',   barcodes: BC_9_16};
3449 28 Jul 15 olle 23 var IS_B3 = {color: 'bg-blue',   barcodes: BC_18_27};
3449 28 Jul 15 olle 24
3449 28 Jul 15 olle 25 var IS_B4 = {color: 'bg-blue-dk',   barcodes: BC_8_1};
3449 28 Jul 15 olle 26 var IS_B5 = {color: 'bg-blue-dk',   barcodes: BC_16_9};
3449 28 Jul 15 olle 27 var IS_B6 = {color: 'bg-blue-dk',   barcodes: BC_27_18};
3449 28 Jul 15 olle 28
3449 28 Jul 15 olle 29 var IS_Y1 = {color: 'bg-yellow', barcodes: BC_1_8};
3449 28 Jul 15 olle 30 var IS_Y2 = {color: 'bg-yellow', barcodes: BC_9_16};
3449 28 Jul 15 olle 31 var IS_Y3 = {color: 'bg-yellow', barcodes: BC_18_27};
3449 28 Jul 15 olle 32
3449 28 Jul 15 olle 33 var IS_Y4 = {color: 'bg-yellow-dk', barcodes: BC_8_1};
3449 28 Jul 15 olle 34 var IS_Y5 = {color: 'bg-yellow-dk', barcodes: BC_16_9};
3449 28 Jul 15 olle 35 var IS_Y6 = {color: 'bg-yellow-dk', barcodes: BC_27_18};
3449 28 Jul 15 olle 36
3449 28 Jul 15 olle 37
3449 28 Jul 15 olle 38 var POOL_SCHEMA =
3449 28 Jul 15 olle 39 [
3449 28 Jul 15 olle 40   {
3449 28 Jul 15 olle 41     id: '2by48',
3449 28 Jul 15 olle 42     name: '2 pools × 48 samples',
3449 28 Jul 15 olle 43     type: 'manual',
3449 28 Jul 15 olle 44      numPools: 2,
3449 28 Jul 15 olle 45      numWellsPerPool: 48,
3449 28 Jul 15 olle 46      columnClasses: ['pool-left', 'pool-part2', 'pool-part3','pool-part4', 'pool-part5', 'pool-right'],
3449 28 Jul 15 olle 47     barcodeVariants:
3449 28 Jul 15 olle 48       [
3449 28 Jul 15 olle 49          {name: 'A-B', indexSets: [IS_G1, IS_G2, IS_G3, IS_G4, IS_G5, IS_G6, IS_B1, IS_B2, IS_B3, IS_B4, IS_B5, IS_B6]},
3449 28 Jul 15 olle 50          {name: 'B-C', indexSets: [IS_B1, IS_B2, IS_B3, IS_B4, IS_B5, IS_B6, IS_Y1, IS_Y2, IS_Y3, IS_Y4, IS_Y5, IS_Y6]},
3449 28 Jul 15 olle 51          {name: 'C-A', indexSets: [IS_Y1, IS_Y2, IS_Y3, IS_Y4, IS_Y5, IS_Y6, IS_G1, IS_G2, IS_G3, IS_G4, IS_G5, IS_G6]}
3449 28 Jul 15 olle 52       ],
3449 28 Jul 15 olle 53
3449 28 Jul 15 olle 54     getPoolNumForColumn: function(colNum)
3449 28 Jul 15 olle 55     {
3449 28 Jul 15 olle 56       var poolNum = Math.floor(colNum / 6);
3449 28 Jul 15 olle 57       return poolNum;
3449 28 Jul 15 olle 58     },
3449 28 Jul 15 olle 59
3449 28 Jul 15 olle 60      getClassNameForWell: function(well)
3449 28 Jul 15 olle 61     {
3449 28 Jul 15 olle 62       var c = well.column;
3449 28 Jul 15 olle 63       var cls = 'primary ';
3449 28 Jul 15 olle 64       cls += this.columnClasses[c % 6];
3449 28 Jul 15 olle 65       return cls;
3449 28 Jul 15 olle 66     },
3449 28 Jul 15 olle 67     
3449 28 Jul 15 olle 68     getWellsInPool: function(plate, poolNum)
3449 28 Jul 15 olle 69     {
3449 28 Jul 15 olle 70       var result = [];
3449 28 Jul 15 olle 71       var index = poolNum * this.numWellsPerPool;
3449 28 Jul 15 olle 72       while (result.length < this.numWellsPerPool && index < plate.wells.length)
3449 28 Jul 15 olle 73       {
3449 28 Jul 15 olle 74         result[result.length] = plate.wells[index];
3449 28 Jul 15 olle 75         index++;
3449 28 Jul 15 olle 76       }
3449 28 Jul 15 olle 77       return result;
3449 28 Jul 15 olle 78     }
3449 28 Jul 15 olle 79   
3449 28 Jul 15 olle 80   },
3449 28 Jul 15 olle 81   {
3449 28 Jul 15 olle 82     id: '4by24',
3449 28 Jul 15 olle 83     name: '4 pools × 24 samples',
3449 28 Jul 15 olle 84     type: 'manual',
3449 28 Jul 15 olle 85      numPools: 4,
3449 28 Jul 15 olle 86      numWellsPerPool: 24,
3449 28 Jul 15 olle 87      columnClasses: ['pool-left', 'pool-middle', 'pool-right'],
3449 28 Jul 15 olle 88     barcodeVariants:
3449 28 Jul 15 olle 89       [
3449 28 Jul 15 olle 90          {
3449 28 Jul 15 olle 91            name: 'A-B-C-D', 
3449 28 Jul 15 olle 92            indexSets: [IS_G1, IS_B2, IS_Y3, IS_G1, IS_B2, IS_Y6, IS_G4, IS_B5, IS_Y3, IS_G4, IS_B5, IS_Y6]
3449 28 Jul 15 olle 93          },
3449 28 Jul 15 olle 94          {
3449 28 Jul 15 olle 95            name: 'A-A-A-A', 
3449 28 Jul 15 olle 96            indexSets: [IS_G1, IS_B2, IS_Y3, IS_G1, IS_B2, IS_Y3, IS_G1, IS_B2, IS_Y3, IS_G1, IS_B2, IS_Y3]
3449 28 Jul 15 olle 97          },
3449 28 Jul 15 olle 98          {
3449 28 Jul 15 olle 99            /* Same as A-A-A-A, kept for backwards compatibility */
3449 28 Jul 15 olle 100            name: 'FULL', 
3449 28 Jul 15 olle 101            disabled: 1,
3449 28 Jul 15 olle 102            indexSets: [IS_G1, IS_B2, IS_Y3, IS_G1, IS_B2, IS_Y3, IS_G1, IS_B2, IS_Y3, IS_G1, IS_B2, IS_Y3]
3449 28 Jul 15 olle 103          }
3449 28 Jul 15 olle 104       ],
3449 28 Jul 15 olle 105
3449 28 Jul 15 olle 106     getPoolNumForColumn: function(colNum)
3449 28 Jul 15 olle 107     {
3449 28 Jul 15 olle 108       var poolNum = Math.floor(colNum / 3);
3449 28 Jul 15 olle 109       return poolNum;
3449 28 Jul 15 olle 110     },
3449 28 Jul 15 olle 111
3449 28 Jul 15 olle 112      getClassNameForWell: function(well)
3449 28 Jul 15 olle 113     {
3449 28 Jul 15 olle 114       var c = well.column;
3449 28 Jul 15 olle 115       var cls = 'primary ';
3449 28 Jul 15 olle 116       cls += this.columnClasses[c % 3];
3449 28 Jul 15 olle 117       return cls;
3449 28 Jul 15 olle 118     },
3449 28 Jul 15 olle 119     
3449 28 Jul 15 olle 120     getWellsInPool: function(plate, poolNum)
3449 28 Jul 15 olle 121     {
3449 28 Jul 15 olle 122       var result = [];
3449 28 Jul 15 olle 123       var index = poolNum * this.numWellsPerPool;
3449 28 Jul 15 olle 124       while (result.length < this.numWellsPerPool && index < plate.wells.length)
3449 28 Jul 15 olle 125       {
3449 28 Jul 15 olle 126         result[result.length] = plate.wells[index];
3449 28 Jul 15 olle 127         index++;
3449 28 Jul 15 olle 128       }
3449 28 Jul 15 olle 129       return result;
3449 28 Jul 15 olle 130     }
3449 28 Jul 15 olle 131   
3449 28 Jul 15 olle 132   },
3449 28 Jul 15 olle 133   {
3449 28 Jul 15 olle 134     id: '1by16',
3449 28 Jul 15 olle 135     name: '1 pool × 16 samples',
3449 28 Jul 15 olle 136     type: 'manual',
3449 28 Jul 15 olle 137     numPools: 1,
3449 28 Jul 15 olle 138     numWellsPerPool: 16,
3449 28 Jul 15 olle 139     columnClasses: ['pool-right', 'pool-left'],
3449 28 Jul 15 olle 140     barcodeVariants:
3449 28 Jul 15 olle 141       [
3449 28 Jul 15 olle 142          {name: 'A', indexSets: [null, null, null, null, null, IS_G1, IS_G2, null, null, null, null, null]},
3449 28 Jul 15 olle 143          {name: 'B', indexSets: [null, null, null, null, null, IS_B2, IS_B3, null, null, null, null, null]},
3449 28 Jul 15 olle 144          {name: 'C', indexSets: [null, null, null, null, null, IS_Y3, IS_Y1, null, null, null, null, null]}
3449 28 Jul 15 olle 145       ],
3449 28 Jul 15 olle 146     
3449 28 Jul 15 olle 147     getPoolNumForColumn: function(colNum)
3449 28 Jul 15 olle 148     {
3449 28 Jul 15 olle 149       var poolNum = -1;
3449 28 Jul 15 olle 150       if (colNum == 5 || colNum == 6)
3449 28 Jul 15 olle 151       {
3449 28 Jul 15 olle 152         poolNum = 0;
3449 28 Jul 15 olle 153       }
3449 28 Jul 15 olle 154       return poolNum;
3449 28 Jul 15 olle 155     },
3449 28 Jul 15 olle 156        
3449 28 Jul 15 olle 157     getClassNameForWell: function(well)
3449 28 Jul 15 olle 158     {
3449 28 Jul 15 olle 159       var c = well.column;
3449 28 Jul 15 olle 160       var cls = (c == 5 || c == 6) ? 'primary ' : 'secondary ';
3449 28 Jul 15 olle 161       cls += (c >= 4 && c <= 7) ? this.columnClasses[c % 2] : '';
3449 28 Jul 15 olle 162       return cls;
3449 28 Jul 15 olle 163     },
3449 28 Jul 15 olle 164       
3449 28 Jul 15 olle 165     getWellsInPool: function(plate, poolNum)
3449 28 Jul 15 olle 166     {
3449 28 Jul 15 olle 167       var result = [];
3449 28 Jul 15 olle 168       var index = poolNum*this.numWellsPerPool+5*plate.rows;
3449 28 Jul 15 olle 169       while (result.length < this.numWellsPerPool && index < plate.wells.length)
3449 28 Jul 15 olle 170       {
3449 28 Jul 15 olle 171         result[result.length] = plate.wells[index];
3449 28 Jul 15 olle 172         index++;
3449 28 Jul 15 olle 173       }
3449 28 Jul 15 olle 174       return result;
3449 28 Jul 15 olle 175     }
3449 28 Jul 15 olle 176   },
3449 28 Jul 15 olle 177   {
3449 28 Jul 15 olle 178     id: '2by16',
3449 28 Jul 15 olle 179     name: '2 pools × 16 samples',
3449 28 Jul 15 olle 180     type: 'manual',
3449 28 Jul 15 olle 181      numPools: 2,
3449 28 Jul 15 olle 182      numWellsPerPool: 16,
3449 28 Jul 15 olle 183      columnClasses: ['pool-left', 'pool-right'],
3449 28 Jul 15 olle 184     barcodeVariants:
3449 28 Jul 15 olle 185       [
3449 28 Jul 15 olle 186          {name: 'A-B', indexSets: [null, null, null, null, IS_G1, IS_G2, IS_B3, IS_B1, null, null, null, null]},
3449 28 Jul 15 olle 187          {name: 'B-C', indexSets: [null, null, null, null, IS_B3, IS_B1, IS_Y2, IS_Y3, null, null, null, null]},
3449 28 Jul 15 olle 188          {name: 'C-A', indexSets: [null, null, null, null, IS_Y2, IS_Y3, IS_G1, IS_G2, null, null, null, null]}
3449 28 Jul 15 olle 189       ],
3449 28 Jul 15 olle 190
3449 28 Jul 15 olle 191     getPoolNumForColumn: function(colNum)
3449 28 Jul 15 olle 192     {
3449 28 Jul 15 olle 193       var poolNum = -1;
3449 28 Jul 15 olle 194       if (colNum >= 4 && colNum <= 7)
3449 28 Jul 15 olle 195       {
3449 28 Jul 15 olle 196         poolNum = Math.floor((colNum - 4) / 2);
3449 28 Jul 15 olle 197       }
3449 28 Jul 15 olle 198       return poolNum;
3449 28 Jul 15 olle 199     },
3449 28 Jul 15 olle 200      
3449 28 Jul 15 olle 201      getClassNameForWell: function(well)
3449 28 Jul 15 olle 202     {
3449 28 Jul 15 olle 203       var c = well.column;
3449 28 Jul 15 olle 204       var cls = (c >= 4 && c <= 7) ? 'primary ' : 'secondary ';
3449 28 Jul 15 olle 205       if (c >= 3 && c <= 8) cls += this.columnClasses[c % 2];
3449 28 Jul 15 olle 206       return cls;
3449 28 Jul 15 olle 207     },
3449 28 Jul 15 olle 208     
3449 28 Jul 15 olle 209     getWellsInPool: function(plate, poolNum)
3449 28 Jul 15 olle 210      {
3449 28 Jul 15 olle 211        var result = [];
3449 28 Jul 15 olle 212        var index = poolNum*this.numWellsPerPool + 4 * plate.rows;
3449 28 Jul 15 olle 213       while (result.length < this.numWellsPerPool && index < plate.wells.length)
3449 28 Jul 15 olle 214       {
3449 28 Jul 15 olle 215         result[result.length] = plate.wells[index];
3449 28 Jul 15 olle 216         index++;
3449 28 Jul 15 olle 217       }
3449 28 Jul 15 olle 218        return result;
3449 28 Jul 15 olle 219      }
3449 28 Jul 15 olle 220    },
3449 28 Jul 15 olle 221   {
3449 28 Jul 15 olle 222     id: '3by16',
3449 28 Jul 15 olle 223     name: '3 pools × 16 samples',
3449 28 Jul 15 olle 224     type: 'manual',
3449 28 Jul 15 olle 225     numPools: 3,
3449 28 Jul 15 olle 226     numWellsPerPool: 16,
3449 28 Jul 15 olle 227     columnClasses: ['pool-right', 'pool-left'],
3449 28 Jul 15 olle 228     barcodeVariants:
3449 28 Jul 15 olle 229       [
3449 28 Jul 15 olle 230          {name: 'A-B-C', indexSets: [null, null, null, IS_G1, IS_G2, IS_B3, IS_B1, IS_Y2, IS_Y3, null, null, null, null]},
3449 28 Jul 15 olle 231          {name: 'B-C-A', indexSets: [null, null, null, IS_B3, IS_B1, IS_Y2, IS_Y3, IS_G1, IS_G2, null, null, null, null]},
3449 28 Jul 15 olle 232          {name: 'C-A-B', indexSets: [null, null, null, IS_Y2, IS_Y3, IS_G1, IS_G2, IS_B3, IS_B2, null, null, null, null]}
3449 28 Jul 15 olle 233       ],
3449 28 Jul 15 olle 234     
3449 28 Jul 15 olle 235     getPoolNumForColumn: function(colNum)
3449 28 Jul 15 olle 236     {
3449 28 Jul 15 olle 237       var poolNum = -1;
3449 28 Jul 15 olle 238       if (colNum >= 3 && colNum <= 8)
3449 28 Jul 15 olle 239       {
3449 28 Jul 15 olle 240         poolNum = Math.floor((colNum - 3) / 2);
3449 28 Jul 15 olle 241       }
3449 28 Jul 15 olle 242       return poolNum;
3449 28 Jul 15 olle 243     },
3449 28 Jul 15 olle 244        
3449 28 Jul 15 olle 245     getClassNameForWell: function(well)
3449 28 Jul 15 olle 246     {
3449 28 Jul 15 olle 247       var c = well.column;
3449 28 Jul 15 olle 248       var cls = (c >= 3 && c <= 8) ? 'primary ' : 'secondary ';
3449 28 Jul 15 olle 249       if (c >= 2 && c <= 9) cls += this.columnClasses[c % 2];
3449 28 Jul 15 olle 250       return cls;
3449 28 Jul 15 olle 251     },
3449 28 Jul 15 olle 252       
3449 28 Jul 15 olle 253     getWellsInPool: function(plate, poolNum)
3449 28 Jul 15 olle 254     {
3449 28 Jul 15 olle 255       var result = [];
3449 28 Jul 15 olle 256        var index = poolNum*this.numWellsPerPool + 3 * plate.rows;
3449 28 Jul 15 olle 257       while (result.length < this.numWellsPerPool && index < plate.wells.length)
3449 28 Jul 15 olle 258       {
3449 28 Jul 15 olle 259         result[result.length] = plate.wells[index];
3449 28 Jul 15 olle 260         index++;
3449 28 Jul 15 olle 261       }
3449 28 Jul 15 olle 262       return result;
3449 28 Jul 15 olle 263     }
3449 28 Jul 15 olle 264   },
3449 28 Jul 15 olle 265   {
3449 28 Jul 15 olle 266     id: '4by16',
3449 28 Jul 15 olle 267     name: '4 pools × 16 samples',
3449 28 Jul 15 olle 268     type: 'manual',
3449 28 Jul 15 olle 269      numPools: 4,
3449 28 Jul 15 olle 270      numWellsPerPool: 16,
3449 28 Jul 15 olle 271      columnClasses: ['pool-left', 'pool-right'],
3449 28 Jul 15 olle 272     barcodeVariants:
3449 28 Jul 15 olle 273       [
3449 28 Jul 15 olle 274          {name: 'A-B-C-A', indexSets: [null, null, IS_G1, IS_G2, IS_B3, IS_B1, IS_Y2, IS_Y3, IS_G1, IS_G2, null, null]},
3449 28 Jul 15 olle 275          {name: 'B-C-A-B', indexSets: [null, null, IS_B3, IS_B1, IS_Y2, IS_Y3, IS_G1, IS_G2, IS_B3, IS_B1, null, null]},
3449 28 Jul 15 olle 276          {name: 'C-A-B-C', indexSets: [null, null, IS_Y2, IS_Y3, IS_G1, IS_G2, IS_B3, IS_B1, IS_Y2, IS_Y3, null, null]}
3449 28 Jul 15 olle 277       ],
3449 28 Jul 15 olle 278
3449 28 Jul 15 olle 279     getPoolNumForColumn: function(colNum)
3449 28 Jul 15 olle 280     {
3449 28 Jul 15 olle 281       var poolNum = -1;
3449 28 Jul 15 olle 282       if (colNum >= 2 && colNum <= 9)
3449 28 Jul 15 olle 283       {
3449 28 Jul 15 olle 284         poolNum = Math.floor((colNum - 2) / 2);
3449 28 Jul 15 olle 285       }
3449 28 Jul 15 olle 286       return poolNum;
3449 28 Jul 15 olle 287     },
3449 28 Jul 15 olle 288      
3449 28 Jul 15 olle 289      getClassNameForWell: function(well)
3449 28 Jul 15 olle 290     {
3449 28 Jul 15 olle 291       var c = well.column;
3449 28 Jul 15 olle 292       var cls = (c >= 2 && c <= 9) ? 'primary ' : 'secondary ';
3449 28 Jul 15 olle 293       if (c >= 1 && c <= 10) cls += this.columnClasses[c % 2];
3449 28 Jul 15 olle 294       return cls;
3449 28 Jul 15 olle 295     },
3449 28 Jul 15 olle 296     
3449 28 Jul 15 olle 297     getWellsInPool: function(plate, poolNum)
3449 28 Jul 15 olle 298      {
3449 28 Jul 15 olle 299        var result = [];
3449 28 Jul 15 olle 300        var index = poolNum*this.numWellsPerPool + 2 * plate.rows;
3449 28 Jul 15 olle 301       while (result.length < this.numWellsPerPool && index < plate.wells.length)
3449 28 Jul 15 olle 302       {
3449 28 Jul 15 olle 303         result[result.length] = plate.wells[index];
3449 28 Jul 15 olle 304         index++;
3449 28 Jul 15 olle 305       }
3449 28 Jul 15 olle 306        return result;
3449 28 Jul 15 olle 307      }
3449 28 Jul 15 olle 308    },
3449 28 Jul 15 olle 309   {
3449 28 Jul 15 olle 310     id: '5by16',
3449 28 Jul 15 olle 311     name: '5 pools × 16 samples',
3449 28 Jul 15 olle 312     type: 'manual',
3449 28 Jul 15 olle 313     numPools: 5,
3449 28 Jul 15 olle 314     numWellsPerPool: 16,
3449 28 Jul 15 olle 315     columnClasses: ['pool-right', 'pool-left'],
3449 28 Jul 15 olle 316     barcodeVariants:
3449 28 Jul 15 olle 317       [
3449 28 Jul 15 olle 318          {name: 'A-B-C-A-B', indexSets: [null, IS_G1, IS_G2, IS_B3, IS_B1, IS_Y2, IS_Y3, IS_G1, IS_G2, IS_B3, IS_B1, null]},
3449 28 Jul 15 olle 319          {name: 'B-C-A-B-C', indexSets: [null, IS_B3, IS_B1, IS_Y2, IS_Y3, IS_G1, IS_G2, IS_B3, IS_B1, IS_Y2, IS_Y3, null]},
3449 28 Jul 15 olle 320          {name: 'C-A-B-C-A', indexSets: [null, IS_Y2, IS_Y3, IS_G1, IS_G2, IS_B3, IS_B1, IS_Y2, IS_Y3, IS_G1, IS_G2, null]}
3449 28 Jul 15 olle 321       ],
3449 28 Jul 15 olle 322   
3449 28 Jul 15 olle 323     getPoolNumForColumn: function(colNum)
3449 28 Jul 15 olle 324     {
3449 28 Jul 15 olle 325       var poolNum = -1;
3449 28 Jul 15 olle 326       if (colNum >= 1 && colNum <= 10)
3449 28 Jul 15 olle 327       {
3449 28 Jul 15 olle 328         poolNum = Math.floor((colNum-1) / 2);
3449 28 Jul 15 olle 329       }
3449 28 Jul 15 olle 330       return poolNum;
3449 28 Jul 15 olle 331     },
3449 28 Jul 15 olle 332      
3449 28 Jul 15 olle 333     getClassNameForWell: function(well)
3449 28 Jul 15 olle 334     {
3449 28 Jul 15 olle 335       var c = well.column;
3449 28 Jul 15 olle 336       var cls = (c >= 1 && c <= 10) ? 'primary ' : 'secondary ';
3449 28 Jul 15 olle 337       cls += this.columnClasses[c % 2];
3449 28 Jul 15 olle 338       return cls;
3449 28 Jul 15 olle 339     },
3449 28 Jul 15 olle 340     
3449 28 Jul 15 olle 341     getWellsInPool: function(plate, poolNum)
3449 28 Jul 15 olle 342      {
3449 28 Jul 15 olle 343        var result = [];
3449 28 Jul 15 olle 344        var index = poolNum*this.numWellsPerPool+plate.rows;
3449 28 Jul 15 olle 345       while (result.length < this.numWellsPerPool && index < plate.wells.length)
3449 28 Jul 15 olle 346       {
3449 28 Jul 15 olle 347         result[result.length] = plate.wells[index];
3449 28 Jul 15 olle 348         index++;
3449 28 Jul 15 olle 349       }
3449 28 Jul 15 olle 350        return result;
3449 28 Jul 15 olle 351      }
3449 28 Jul 15 olle 352   },
3449 28 Jul 15 olle 353   {
3449 28 Jul 15 olle 354     id: 'NP1by16',
3449 28 Jul 15 olle 355     name: '1 pool × 16 samples',
3449 28 Jul 15 olle 356     type: 'neoprep',
3449 28 Jul 15 olle 357     numPools: 1,
3449 28 Jul 15 olle 358     numWellsPerPool: 16,
3449 28 Jul 15 olle 359     columnClasses: ['pool-left', 'pool-right'],
3449 28 Jul 15 olle 360     barcodeVariants:
3449 28 Jul 15 olle 361       [
3449 28 Jul 15 olle 362          {name: 'A', indexSets: [IS_G1, IS_G2]},
3449 28 Jul 15 olle 363          {name: 'B', indexSets: [IS_B2, IS_B3]},
3449 28 Jul 15 olle 364          {name: 'C', indexSets: [IS_Y3, IS_Y1]}
3449 28 Jul 15 olle 365       ],
3449 28 Jul 15 olle 366     
3449 28 Jul 15 olle 367     getPoolNumForColumn: function(colNum)
3449 28 Jul 15 olle 368     {
3449 28 Jul 15 olle 369       var poolNum = -1;
3449 28 Jul 15 olle 370       if (colNum == 0 || colNum == 1)
3449 28 Jul 15 olle 371       {
3449 28 Jul 15 olle 372         poolNum = 0;
3449 28 Jul 15 olle 373       }
3449 28 Jul 15 olle 374       return poolNum;
3449 28 Jul 15 olle 375     },
3449 28 Jul 15 olle 376        
3449 28 Jul 15 olle 377     getClassNameForWell: function(well)
3449 28 Jul 15 olle 378     {
3449 28 Jul 15 olle 379       var c = well.column;
3449 28 Jul 15 olle 380       var cls = (c == 0 || c == 1) ? 'primary ' : 'secondary ';
3449 28 Jul 15 olle 381       cls += (c >= 0 && c <= 1) ? this.columnClasses[c % 2] : '';
3449 28 Jul 15 olle 382       return cls;
3449 28 Jul 15 olle 383     },
3449 28 Jul 15 olle 384       
3449 28 Jul 15 olle 385     getWellsInPool: function(plate, poolNum)
3449 28 Jul 15 olle 386     {
3449 28 Jul 15 olle 387       var result = [];
3449 28 Jul 15 olle 388       var index = poolNum*this.numWellsPerPool;
3449 28 Jul 15 olle 389       while (result.length < this.numWellsPerPool && index < plate.wells.length)
3449 28 Jul 15 olle 390       {
3449 28 Jul 15 olle 391         result[result.length] = plate.wells[index];
3449 28 Jul 15 olle 392         index++;
3449 28 Jul 15 olle 393       }
3449 28 Jul 15 olle 394       return result;
3449 28 Jul 15 olle 395     }
3449 28 Jul 15 olle 396   },
3449 28 Jul 15 olle 397   {
3449 28 Jul 15 olle 398     id: 'NP2by8',
3449 28 Jul 15 olle 399     name: '2 pools × 8 samples',
3449 28 Jul 15 olle 400     type: 'neoprep',
3449 28 Jul 15 olle 401     numPools: 2,
3449 28 Jul 15 olle 402     numWellsPerPool: 8,
3449 28 Jul 15 olle 403     barcodeVariants:
3449 28 Jul 15 olle 404       [
3449 28 Jul 15 olle 405          {name: 'A-B', indexSets: [IS_G1, IS_G2]},
3449 28 Jul 15 olle 406          {name: 'B-C', indexSets: [IS_B2, IS_B3]},
3449 28 Jul 15 olle 407          {name: 'C-A', indexSets: [IS_Y3, IS_Y1]}
3449 28 Jul 15 olle 408       ],
3449 28 Jul 15 olle 409     
3449 28 Jul 15 olle 410     getPoolNumForColumn: function(colNum)
3449 28 Jul 15 olle 411     {
3449 28 Jul 15 olle 412       var poolNum = -1;
3449 28 Jul 15 olle 413       if (colNum == 0 || colNum == 1)
3449 28 Jul 15 olle 414       {
3449 28 Jul 15 olle 415         poolNum = colNum;
3449 28 Jul 15 olle 416       }
3449 28 Jul 15 olle 417       return poolNum;
3449 28 Jul 15 olle 418     },
3449 28 Jul 15 olle 419        
3449 28 Jul 15 olle 420     getClassNameForWell: function(well)
3449 28 Jul 15 olle 421     {
3449 28 Jul 15 olle 422       var c = well.column;
3449 28 Jul 15 olle 423       var cls = (c == 0 || c == 1) ? 'primary pool-left pool-right' : 'secondary ';
3449 28 Jul 15 olle 424       return cls;
3449 28 Jul 15 olle 425     },
3449 28 Jul 15 olle 426       
3449 28 Jul 15 olle 427     getWellsInPool: function(plate, poolNum)
3449 28 Jul 15 olle 428     {
3449 28 Jul 15 olle 429       var result = [];
3449 28 Jul 15 olle 430       var index = poolNum*this.numWellsPerPool;
3449 28 Jul 15 olle 431       while (result.length < this.numWellsPerPool && index < plate.wells.length)
3449 28 Jul 15 olle 432       {
3449 28 Jul 15 olle 433         result[result.length] = plate.wells[index];
3449 28 Jul 15 olle 434         index++;
3449 28 Jul 15 olle 435       }
3449 28 Jul 15 olle 436       return result;
3449 28 Jul 15 olle 437     }
3449 28 Jul 15 olle 438   }
3449 28 Jul 15 olle 439
3449 28 Jul 15 olle 440 ];
3449 28 Jul 15 olle 441
3449 28 Jul 15 olle 442 /**
3449 28 Jul 15 olle 443   Methods for handling pooling layout schemas.
3449 28 Jul 15 olle 444 */
3449 28 Jul 15 olle 445 var PoolSchema = function()
3449 28 Jul 15 olle 446 {
3449 28 Jul 15 olle 447   var ps = {};
3449 28 Jul 15 olle 448   
3449 28 Jul 15 olle 449   ps.initList = function(list, selectedId, type)
3449 28 Jul 15 olle 450   {
3449 28 Jul 15 olle 451     var selectedSchema = null;
3449 28 Jul 15 olle 452     for (var i = 0; i < POOL_SCHEMA.length; i++)
3449 28 Jul 15 olle 453     {
3449 28 Jul 15 olle 454       var schema = POOL_SCHEMA[i];
3449 28 Jul 15 olle 455       if (!type || schema.type == type)
3449 28 Jul 15 olle 456       {
3449 28 Jul 15 olle 457         var option = new Option(schema.name, schema.id);
3449 28 Jul 15 olle 458         list[list.length] = option;
3449 28 Jul 15 olle 459         if (selectedId == schema.id || selectedSchema == null) 
3449 28 Jul 15 olle 460         {
3449 28 Jul 15 olle 461           selectedSchema = schema;
3449 28 Jul 15 olle 462           list.selectedIndex = list.length-1;
3449 28 Jul 15 olle 463         }
3449 28 Jul 15 olle 464       }
3449 28 Jul 15 olle 465     }
3449 28 Jul 15 olle 466     return selectedSchema;
3449 28 Jul 15 olle 467   }
3449 28 Jul 15 olle 468   
3449 28 Jul 15 olle 469   ps.initVariantList = function(list, schema, selectedId)
3449 28 Jul 15 olle 470   {
3449 28 Jul 15 olle 471     if (!selectedId) selectedId = schema.barcodeVariants[0].name;
3449 28 Jul 15 olle 472     var selectedIndex = 0;
3449 28 Jul 15 olle 473     list.length = 0;
3449 28 Jul 15 olle 474     for (var i = 0; i < schema.barcodeVariants.length; i++)
3449 28 Jul 15 olle 475     {
3449 28 Jul 15 olle 476       var variant = schema.barcodeVariants[i];
3449 28 Jul 15 olle 477       if (!variant.disabled)
3449 28 Jul 15 olle 478       {
3449 28 Jul 15 olle 479         var option = new Option(variant.name, variant.name);
3449 28 Jul 15 olle 480         list[list.length] = option;
3449 28 Jul 15 olle 481         if (selectedId == variant.name) selectedIndex = i;
3449 28 Jul 15 olle 482       }
3449 28 Jul 15 olle 483     }
3449 28 Jul 15 olle 484     list.selectedIndex = selectedIndex;
3449 28 Jul 15 olle 485     return schema.barcodeVariants[selectedIndex];
3449 28 Jul 15 olle 486   }
3449 28 Jul 15 olle 487   
3449 28 Jul 15 olle 488   ps.getById = function(schemaId)
3449 28 Jul 15 olle 489   {
3449 28 Jul 15 olle 490     for (var i = 0; i < POOL_SCHEMA.length; i++)
3449 28 Jul 15 olle 491     {
3449 28 Jul 15 olle 492       if (POOL_SCHEMA[i].id == schemaId)
3449 28 Jul 15 olle 493       {
3449 28 Jul 15 olle 494         return POOL_SCHEMA[i];
3449 28 Jul 15 olle 495       }
3449 28 Jul 15 olle 496     }
3449 28 Jul 15 olle 497     return null;
3449 28 Jul 15 olle 498   }
3449 28 Jul 15 olle 499   
3449 28 Jul 15 olle 500   ps.getBarcodeVariantByName = function(schema, barcodeVariant)
3449 28 Jul 15 olle 501   {
3449 28 Jul 15 olle 502     for (var i = 0; i < schema.barcodeVariants.length; i++)
3449 28 Jul 15 olle 503     {
3449 28 Jul 15 olle 504       if (barcodeVariant == schema.barcodeVariants[i].name) 
3449 28 Jul 15 olle 505       {
3449 28 Jul 15 olle 506         return schema.barcodeVariants[i];
3449 28 Jul 15 olle 507       }
3449 28 Jul 15 olle 508     }
3449 28 Jul 15 olle 509     return schema.barcodeVariants[0];
3449 28 Jul 15 olle 510   }
3449 28 Jul 15 olle 511   
3449 28 Jul 15 olle 512   ps.buildPoolTableRow = function(schema, columns, interactive, prefix, suffix)
3449 28 Jul 15 olle 513   {
3449 28 Jul 15 olle 514     if (!prefix) prefix = '';
3449 28 Jul 15 olle 515     if (!suffix) suffix = '';
3449 28 Jul 15 olle 516     var html = '<th></th>';
3449 28 Jul 15 olle 517     var colNum = 0;
3449 28 Jul 15 olle 518     var poolClass = interactive ? 'pool link' : 'pool';
3449 28 Jul 15 olle 519     var afterPool = false;
3449 28 Jul 15 olle 520     while (colNum < columns)
3449 28 Jul 15 olle 521     {
3449 28 Jul 15 olle 522       var poolNum = schema ? schema.getPoolNumForColumn(colNum) : -1;
3449 28 Jul 15 olle 523       var colspan = 1;
3449 28 Jul 15 olle 524       if (poolNum == -1)
3449 28 Jul 15 olle 525       {
3449 28 Jul 15 olle 526         while (colNum+colspan < columns)
3449 28 Jul 15 olle 527         {
3449 28 Jul 15 olle 528           if (schema.getPoolNumForColumn(colNum+colspan) != -1) break;
3449 28 Jul 15 olle 529           colspan++;
3449 28 Jul 15 olle 530         }
3449 28 Jul 15 olle 531         var className = afterPool ? 'nopool-after-pool' : 'nopool-before-pool';
3449 28 Jul 15 olle 532         html += '<th class="'+className+'" colspan="'+colspan+'">&nbsp;</th>';
3449 28 Jul 15 olle 533       }
3449 28 Jul 15 olle 534       else
3449 28 Jul 15 olle 535       {
3449 28 Jul 15 olle 536         while (colNum+colspan < columns)
3449 28 Jul 15 olle 537         {
3449 28 Jul 15 olle 538           if (schema.getPoolNumForColumn(colNum+colspan) != poolNum) break;
3449 28 Jul 15 olle 539           colspan++;
3449 28 Jul 15 olle 540         }
3449 28 Jul 15 olle 541         html += '<th id="pool.' + poolNum + '" colspan="'+colspan+'"';
3449 28 Jul 15 olle 542         html += ' class="'+poolClass+'"';
3449 28 Jul 15 olle 543         html += ' data-pool-num="' + poolNum + '"';
3449 28 Jul 15 olle 544         html += '>'+POOL_NAMES[poolNum]+'</th>';
3449 28 Jul 15 olle 545         afterPool = true;
3449 28 Jul 15 olle 546       }
3449 28 Jul 15 olle 547       colNum += colspan;
3449 28 Jul 15 olle 548     }
3449 28 Jul 15 olle 549     
3449 28 Jul 15 olle 550     var row = document.getElementById('pool-row');
3449 28 Jul 15 olle 551     row.innerHTML = prefix+html+suffix;
3449 28 Jul 15 olle 552   }
3449 28 Jul 15 olle 553   
3449 28 Jul 15 olle 554   return ps;
3449 28 Jul 15 olle 555 }();
3449 28 Jul 15 olle 556
3449 28 Jul 15 olle 557
3449 28 Jul 15 olle 558 var PoolMix = function()
3449 28 Jul 15 olle 559 {
3449 28 Jul 15 olle 560   
3449 28 Jul 15 olle 561   var LIMIT_FOR_EXTRA_LARGE_MIX = 1.0;
3449 28 Jul 15 olle 562   var AVAILABLE_VOLUME = 10.0;
3449 28 Jul 15 olle 563   var AVAILABLE_VOLUME_AFTER_SPEEDVAC = 5.0;
3449 28 Jul 15 olle 564   
3449 28 Jul 15 olle 565   var pm = {};
3449 28 Jul 15 olle 566   
3449 28 Jul 15 olle 567   /**
3449 28 Jul 15 olle 568     Round the value to the nearest value with 
3449 28 Jul 15 olle 569     the given number of decimals (default=1).
3449 28 Jul 15 olle 570   */
3449 28 Jul 15 olle 571   pm.round = function(value, numDecimals)
3449 28 Jul 15 olle 572   {
3449 28 Jul 15 olle 573     if (!numDecimals) numDecimals = 1;
3449 28 Jul 15 olle 574     var pow = Math.pow(10, numDecimals);
3449 28 Jul 15 olle 575     return Math.round(value * pow) / pow;
3449 28 Jul 15 olle 576   }
3449 28 Jul 15 olle 577   
3449 28 Jul 15 olle 578   /**
3449 28 Jul 15 olle 579     Round the value down to the nearest value with 
3449 28 Jul 15 olle 580     the given number of decimals (default=1).
3449 28 Jul 15 olle 581   */
3449 28 Jul 15 olle 582   pm.floor = function(value, numDecimals)
3449 28 Jul 15 olle 583   {
3449 28 Jul 15 olle 584     if (!numDecimals) numDecimals = 1;
3449 28 Jul 15 olle 585     var pow = Math.pow(10, numDecimals);
3449 28 Jul 15 olle 586     return Math.floor(value * pow) / pow;
3449 28 Jul 15 olle 587   }
3449 28 Jul 15 olle 588   
3449 28 Jul 15 olle 589   /**
3449 28 Jul 15 olle 590     Round the value up to the nearest value with 
3449 28 Jul 15 olle 591     the given number of decimals (default=1).
3449 28 Jul 15 olle 592   */
3449 28 Jul 15 olle 593   pm.ceil = function(value, numDecimals)
3449 28 Jul 15 olle 594   {
3449 28 Jul 15 olle 595     if (!numDecimals) numDecimals = 1;
3449 28 Jul 15 olle 596     var pow = Math.pow(10, numDecimals);
3449 28 Jul 15 olle 597     return Math.ceil(value * pow) / pow;
3449 28 Jul 15 olle 598   }
3449 28 Jul 15 olle 599   
3449 28 Jul 15 olle 600   /**
3449 28 Jul 15 olle 601     Checks if v1 is less than v2 within the given accuracy
3449 28 Jul 15 olle 602     Eg. v1+accuracy <= v2
3449 28 Jul 15 olle 603    */
3449 28 Jul 15 olle 604   pm.lessThan = function(v1, v2, accuracy)
3449 28 Jul 15 olle 605   {
3449 28 Jul 15 olle 606     return v1 + accuracy < v2;
3449 28 Jul 15 olle 607   }
3449 28 Jul 15 olle 608   
3449 28 Jul 15 olle 609   /**
3449 28 Jul 15 olle 610     Calculate the volume of a lib to use for a pool given the
3449 28 Jul 15 olle 611     target molarity for the pool and average volume for each lib
3449 28 Jul 15 olle 612     in the pool. This method calculates two different volumes:
3449 28 Jul 15 olle 613     
3449 28 Jul 15 olle 614     lib.volume = The theoretical volume needed to reach the same
3449 28 Jul 15 olle 615     amount of DNA as the target molarity and volume suggests
3449 28 Jul 15 olle 616     
3449 28 Jul 15 olle 617     lib.actualVolume: The actual volume that can be used due to
3449 28 Jul 15 olle 618     remaining quantity, lib molarity and mixing strategy
3449 28 Jul 15 olle 619     
3449 28 Jul 15 olle 620     The volume is rounded to one decimal in µl.
3449 28 Jul 15 olle 621     
3449 28 Jul 15 olle 622   */
3449 28 Jul 15 olle 623   pm.calculateLibVolume = function(lib, targetMolarity, targetVolume, mixingStrategy)
3449 28 Jul 15 olle 624   {
3449 28 Jul 15 olle 625     var volume = targetVolume * targetMolarity / lib.molarity;
3449 28 Jul 15 olle 626     var mixFactor = 1;
3449 28 Jul 15 olle 627     
3449 28 Jul 15 olle 628     if (pm.lessThan(volume, LIMIT_FOR_EXTRA_LARGE_MIX, 0.05))
3449 28 Jul 15 olle 629     {
3449 28 Jul 15 olle 630       // Mix 'dil' so that we take about 2 times the minimal limit
3449 28 Jul 15 olle 631       mixFactor = Math.max(2 * LIMIT_FOR_EXTRA_LARGE_MIX / volume);
3449 28 Jul 15 olle 632     }
3449 28 Jul 15 olle 633
3449 28 Jul 15 olle 634     // Re-calculate the volume to get the rounding correct (eg. to avoid doubling rounding errors)
3449 28 Jul 15 olle 635     volume = pm.round(mixFactor * volume) / mixFactor;
3449 28 Jul 15 olle 636     
3449 28 Jul 15 olle 637     // This is the theoretical volume that should be used...
3449 28 Jul 15 olle 638     lib.volume = volume;
3449 28 Jul 15 olle 639     lib.eb = null;
3449 28 Jul 15 olle 640     lib.mixFactor = mixFactor;
3449 28 Jul 15 olle 641       
3449 28 Jul 15 olle 642     // However, reality has limitations due to remaining volume, mixing strategy, etc.
3449 28 Jul 15 olle 643     // Check what volume that can actually be used
3449 28 Jul 15 olle 644     if (mixingStrategy == 'fixed')
3449 28 Jul 15 olle 645     {
3449 28 Jul 15 olle 646       // Do not use more than target volume or remaining volume
3449 28 Jul 15 olle 647       volume = Math.min(volume, targetVolume, lib.remainingVolume);
3449 28 Jul 15 olle 648     }
3449 28 Jul 15 olle 649     else
3449 28 Jul 15 olle 650     {
3449 28 Jul 15 olle 651       volume = Math.min(volume, lib.remainingVolume);
3449 28 Jul 15 olle 652     }
3449 28 Jul 15 olle 653     lib.actualVolume = volume;      
3449 28 Jul 15 olle 654   }
3449 28 Jul 15 olle 655   
3449 28 Jul 15 olle 656   /**
3449 28 Jul 15 olle 657     Same as above method except that we already know the mixFactor and actualVolume of
3449 28 Jul 15 olle 658     the lib since that has already been saved to the database.
3449 28 Jul 15 olle 659   */
3449 28 Jul 15 olle 660   pm.calculateLibVolumeForProtocol = function(lib, targetMolarity, targetVolume, mixingStrategy)
3449 28 Jul 15 olle 661   {
3449 28 Jul 15 olle 662     if (lib.mixFactor > 1)
3449 28 Jul 15 olle 663     {
3449 28 Jul 15 olle 664       lib.volume = pm.round(lib.mixFactor * targetVolume * targetMolarity / lib.molarity) / lib.mixFactor;
3449 28 Jul 15 olle 665     }
3449 28 Jul 15 olle 666     else
3449 28 Jul 15 olle 667     {
3449 28 Jul 15 olle 668       lib.volume = pm.round(targetVolume * targetMolarity / lib.molarity);
3449 28 Jul 15 olle 669     }
3449 28 Jul 15 olle 670   }
3449 28 Jul 15 olle 671
3449 28 Jul 15 olle 672   
3449 28 Jul 15 olle 673   /**
3449 28 Jul 15 olle 674     Calculate the volume of EB to mix with a lib.
3449 28 Jul 15 olle 675     
3449 28 Jul 15 olle 676     The volume is rounded to one decimal in µl.
3449 28 Jul 15 olle 677   */
3449 28 Jul 15 olle 678   pm.calculateEbVolume = function(lib, targetMolarity, targetVolume, mixingStrategy)
3449 28 Jul 15 olle 679   {
3449 28 Jul 15 olle 680     var eb = 0;
3449 28 Jul 15 olle 681     if (mixingStrategy == 'fixed')
3449 28 Jul 15 olle 682     {
3449 28 Jul 15 olle 683       eb = targetVolume - lib.volume;
3449 28 Jul 15 olle 684     }
3449 28 Jul 15 olle 685     else if (lib.mixFactor > 1)
3449 28 Jul 15 olle 686     {
3449 28 Jul 15 olle 687       eb = (lib.targetVolume ? lib.targetVolume : targetVolume) - lib.volume;
3449 28 Jul 15 olle 688     }
3449 28 Jul 15 olle 689     
3449 28 Jul 15 olle 690     // This is the theoretical volume that should be used...
3449 28 Jul 15 olle 691     lib.eb = eb;
3449 28 Jul 15 olle 692     lib.mixingStrategy = mixingStrategy;
3449 28 Jul 15 olle 693     
3449 28 Jul 15 olle 694     // However, reality has limitations due to remaining volume, mixing strategy, etc.
3449 28 Jul 15 olle 695     // Check what volume that can actually be used
3449 28 Jul 15 olle 696     if (mixingStrategy == 'fixed' || lib.mixFactor > 1)
3449 28 Jul 15 olle 697     {
3449 28 Jul 15 olle 698       if (pm.lessThan(lib.molarity, targetMolarity, 0.01))
3449 28 Jul 15 olle 699       {
3449 28 Jul 15 olle 700         // Do not dilute if molarity is lower than target molarity
3449 28 Jul 15 olle 701         eb = 0;
3449 28 Jul 15 olle 702       }
3449 28 Jul 15 olle 703       else if (pm.lessThan(lib.actualVolume, lib.volume, 0.05))
3449 28 Jul 15 olle 704       {
3449 28 Jul 15 olle 705         // Reduce EB by the same factor as we have to reduce the volume
3449 28 Jul 15 olle 706         // so the final molarity is still 
3449 28 Jul 15 olle 707         eb = pm.round(eb * lib.actualVolume / lib.volume);
3449 28 Jul 15 olle 708       }
3449 28 Jul 15 olle 709     }    
3449 28 Jul 15 olle 710     lib.actualEb = eb;
3449 28 Jul 15 olle 711   }
3449 28 Jul 15 olle 712
3449 28 Jul 15 olle 713   
3449 28 Jul 15 olle 714   
3449 28 Jul 15 olle 715   /**
3449 28 Jul 15 olle 716     Summarize information for the pool. This will calculate the following and
3449 28 Jul 15 olle 717     return as an object:
3449 28 Jul 15 olle 718     
3449 28 Jul 15 olle 719     libVolume: Total volume of libs in the pool (µl)
3449 28 Jul 15 olle 720     libAmount: Total amount of libs in the pool (nano-mol)
3449 28 Jul 15 olle 721     ebVolumeFromLibs: Total EB volume from mixed directly with libs
3449 28 Jul 15 olle 722     ebVolumeExtra: Extra EB to add to the pool (dynamic mixing)
3449 28 Jul 15 olle 723     molarity: The final pool molarity after mixing everything
3449 28 Jul 15 olle 724   */
3449 28 Jul 15 olle 725   pm.calculateFinalPoolInfo = function(libs, targetMolarity, targetVolume, mixingStrategy)
3449 28 Jul 15 olle 726   {
3449 28 Jul 15 olle 727     var libVolume = 0;
3449 28 Jul 15 olle 728     var libAmount = 0;
3449 28 Jul 15 olle 729     var ebVolumeFromLibs = 0;
3449 28 Jul 15 olle 730     
3449 28 Jul 15 olle 731     for (var libNo = 0; libNo < libs.length; libNo++)
3449 28 Jul 15 olle 732     {
3449 28 Jul 15 olle 733       var lib = libs[libNo];
3449 28 Jul 15 olle 734       
3449 28 Jul 15 olle 735       var volume = lib.actualVolume;
3449 28 Jul 15 olle 736       var eb = lib.actualEb;
3449 28 Jul 15 olle 737
3449 28 Jul 15 olle 738       libVolume += volume;
3449 28 Jul 15 olle 739       ebVolumeFromLibs += eb;
3449 28 Jul 15 olle 740       libAmount += volume * lib.molarity;
3449 28 Jul 15 olle 741     }
3449 28 Jul 15 olle 742     
3449 28 Jul 15 olle 743     var info = {};
3449 28 Jul 15 olle 744     info.libVolume = libVolume;
3449 28 Jul 15 olle 745     info.libAmount = libAmount;
3449 28 Jul 15 olle 746     info.ebVolumeFromLibs = ebVolumeFromLibs;
3449 28 Jul 15 olle 747     
3449 28 Jul 15 olle 748     // Calculate extra EB and total pool volume
3449 28 Jul 15 olle 749     if (mixingStrategy == 'dynamic')
3449 28 Jul 15 olle 750     {
3449 28 Jul 15 olle 751       // Use the target molarity to calculate the total volume
3449 28 Jul 15 olle 752       var targetVolume = pm.round(libAmount / targetMolarity);
3449 28 Jul 15 olle 753       info.ebVolumeExtra = pm.round(targetVolume - info.libVolume - info.ebVolumeFromLibs);
3449 28 Jul 15 olle 754       if (info.ebVolumeExtra < 0)
3449 28 Jul 15 olle 755       {
3449 28 Jul 15 olle 756         info.totalVolume = info.libVolume + info.ebVolumeFromLibs;
3449 28 Jul 15 olle 757       }
3449 28 Jul 15 olle 758       else
3449 28 Jul 15 olle 759       {
3449 28 Jul 15 olle 760         info.totalVolume = targetVolume;
3449 28 Jul 15 olle 761       }
3449 28 Jul 15 olle 762     }
3449 28 Jul 15 olle 763     else
3449 28 Jul 15 olle 764     {
3449 28 Jul 15 olle 765       // No extra EB
3449 28 Jul 15 olle 766       info.ebVolumeExtra = 0;
3449 28 Jul 15 olle 767       info.totalVolume = info.libVolume + info.ebVolumeFromLibs;
3449 28 Jul 15 olle 768     }
3449 28 Jul 15 olle 769     // Calcualate the final molarity (which may be different that target due to rounding)
3449 28 Jul 15 olle 770     info.molarity = info.libAmount / info.totalVolume;
3449 28 Jul 15 olle 771
3449 28 Jul 15 olle 772     return info;
3449 28 Jul 15 olle 773   }
3449 28 Jul 15 olle 774   
3449 28 Jul 15 olle 775   return pm;
3449 28 Jul 15 olle 776 }();