Changeset 2140
- Timestamp:
- Nov 18, 2013, 11:46:46 AM (10 years ago)
- Location:
- extensions/net.sf.basedb.reggie/trunk
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
extensions/net.sf.basedb.reggie/trunk/resources/libprep/create_manual_pool.jsp
r2137 r2140 31 31 32 32 <script language="JavaScript"> 33 var debug = 1;33 var debug = 0; 34 34 var currentStep = 1; 35 35 36 36 var selectedLibraries = []; 37 37 var targetVolumePerLibIsValid = false; 38 var poolInfo; 38 39 39 40 // Loaded from servlet when getting Library information … … 264 265 265 266 266 function calculateRemarks(lib, duplicateBarcodes)267 function calculateRemarks(lib, mixingStrategy, duplicateBarcodes) 267 268 { 268 269 var remarks = []; … … 276 277 } 277 278 278 if (lib.volume > lib.maxVolume) 279 { 280 remarks[remarks.length] = 'Low molarity'; 281 } 282 279 if (lib.volume != lib.actualVolume) 280 { 281 if (lib.volume > lib.remainingVolume) 282 { 283 remarks[remarks.length] = 'Low quantity'; 284 } 285 else 286 { 287 remarks[remarks.length] = 'Low molarity'; 288 } 289 if (mixingStrategy == 'fixed') 290 { 291 remarks[remarks.length] = 'Mix <span class="volume">'+Numbers.formatNumber(lib.actualVolume, 1) + '</span>+<span class="eb">' + Numbers.formatNumber(lib.actualEb, 1)+'µl</span>'; 292 } 293 else 294 { 295 remarks[remarks.length] = 'Use <span class="volume">'+Numbers.formatNumber(lib.actualVolume, 1) + 'µl</span>'; 296 } 297 } 298 283 299 if (lib.speedVacConc != null) 284 300 { … … 286 302 } 287 303 288 if (lib.mixFactor > 1 .001)304 if (lib.mixFactor > 1) 289 305 { 290 306 // Larger mix than default … … 344 360 } 345 361 PoolMix.calculateLibVolume(lib, TARGET_MOLARITY_IN_POOL, targetVolumePerLib, mixingStrategy); 362 PoolMix.calculateEbVolume(lib, TARGET_MOLARITY_IN_POOL, targetVolumePerLib, mixingStrategy); 346 363 } 347 364 } 348 365 349 // Calculate EB350 PoolMix.calculateEbForLibs(libs, TARGET_MOLARITY_IN_POOL, targetVolumePerLib, mixingStrategy);351 352 366 // Calculate final pool volumes, molarity, etc. 353 var poolInfo = PoolMix.calculateFinalPoolInfo(libs, mixingStrategy);367 poolInfo = PoolMix.calculateFinalPoolInfo(libs, TARGET_MOLARITY_IN_POOL, targetVolumePerLib, mixingStrategy); 354 368 355 369 // Make remarks for each lib … … 371 385 lib.hasError = false; 372 386 } 373 if (lib.volume > lib.maxVolume)387 if (lib.volume != lib.actualVolume) 374 388 { 375 389 mark = '*'; … … 380 394 Main.removeClass(tr, 'warning'); 381 395 } 382 setInnerHTML('lib.'+lib.id+'.volume', lib.mixFactor > 1 ? '-' : Numbers.formatNumber(lib.volume *lib.mixFactor, 1)+mark);396 setInnerHTML('lib.'+lib.id+'.volume', lib.mixFactor > 1 ? '-' : Numbers.formatNumber(lib.volume, 1)+mark); 383 397 if (mixingStrategy == 'fixed' && lib.mixFactor < 1.001) 384 398 { 385 setInnerHTML('lib.'+lib.id+'.eb', Numbers.formatNumber(lib.eb *lib.mixFactor, 1));399 setInnerHTML('lib.'+lib.id+'.eb', Numbers.formatNumber(lib.eb, 1)); 386 400 } 387 401 else … … 391 405 } 392 406 393 calculateRemarks(lib, duplicateBarcodes);407 calculateRemarks(lib, mixingStrategy, duplicateBarcodes); 394 408 setInnerHTML('lib.'+lib.id+'.remarks', lib.remarks.join('; ')); 395 409 } 396 410 397 411 var warnMsg = null; 398 if (poolInfo.eb < 0)412 if (poolInfo.ebVolumeExtra < 0) 399 413 { 400 414 warnMsg = 'Too many libs with low molarity'; 401 415 } 402 416 403 setInnerHTML('pool.eb', Numbers.formatNumber(poolInfo.eb FinalMix, 1));417 setInnerHTML('pool.eb', Numbers.formatNumber(poolInfo.ebVolumeExtra, 1)); 404 418 405 419 var poolDiv = document.getElementById('pool-summary'); … … 411 425 if (mixingStrategy == 'dynamic') 412 426 { 413 poolData += ' • <span class="eb">'+Numbers.formatNumber( poolInfo.ebFinalMix, 1, 'µl')+'</span>';427 poolData += ' • <span class="eb">'+Numbers.formatNumber(Math.max(0, poolInfo.ebVolumeExtra), 1, 'µl')+'</span>'; 414 428 } 415 429 if (warnMsg) … … 423 437 setInnerHTML('pool.remarks', ''); 424 438 } 439 425 440 poolData += '</div>'; 426 441 poolDiv.innerHTML = poolData; … … 460 475 var frm = document.forms['reggie']; 461 476 submitInfo.targetVolumeInPoolPerLib = parseFloat(frm.target_volume.value); 477 submitInfo.targetPoolMolarity = TARGET_MOLARITY_IN_POOL; 462 478 submitInfo.mixingStrategy = Forms.getCheckedRadio(frm.mixing_strategy).value; 463 479 464 var poolInfo = {}; 465 poolInfo.name = frm.poolName.value; 466 poolInfo.comment = frm.poolComments.value; 467 poolInfo.libs = []; 468 poolInfo.excluded = []; 480 var pool = {}; 481 pool.name = frm.poolName.value; 482 pool.comment = frm.poolComments.value; 483 pool.ebVolumeExtra = Math.max(0, poolInfo.ebVolumeExtra); 484 pool.libs = []; 485 pool.excluded = []; 469 486 470 487 for (var libNo = 0; libNo < selectedLibraries.length; libNo++) … … 479 496 tmp.id = lib.id; 480 497 tmp.name = lib.name; 481 tmp.volume = Math.min(lib.volume, lib.maxVolume); // Never submit more than max volume482 tmp.eb = Math.max(0, lib.eb); // Never submit negative EB volumes!498 tmp.volume = lib.actualVolume; 499 tmp.eb = lib.actualEb; 483 500 tmp.mixFactor = lib.mixFactor; 484 501 tmp.comment = lib.comment; 485 pool Info.libs[poolInfo.libs.length] = tmp;486 } 487 } 488 submitInfo.pools[submitInfo.pools.length] = pool Info;502 pool.libs[pool.libs.length] = tmp; 503 } 504 } 505 submitInfo.pools[submitInfo.pools.length] = pool; 489 506 490 507 Main.addClass(document.getElementById('step.1.section'), 'disabled'); … … 848 865 </table> 849 866 <div style="margin: 1em; font-style: italic;"> 850 * Low molarity = The concentrationof this library too low to mix to target molarity for the pool.867 * Low quantity = The remaining quantity of this library too low to mix to target molarity for the pool. 851 868 </div> 852 869 </div> -
extensions/net.sf.basedb.reggie/trunk/resources/libprep/create_pools.jsp
r2137 r2140 37 37 38 38 var targetVolumePerLibIsValid = false; 39 var POOL_DATA = []; 39 40 40 41 // Loaded from servlet when getting Library information … … 139 140 var frm = document.forms['reggie']; 140 141 submitInfo.targetVolumeInPoolPerLib = parseFloat(frm.target_volume.value); 142 submitInfo.targetPoolMolarity = TARGET_MOLARITY_IN_POOL; 141 143 submitInfo.mixingStrategy = Forms.getCheckedRadio(frm.mixing_strategy).value; 142 144 … … 149 151 poolInfo.name = POOL_NAMES[poolNo]; 150 152 poolInfo.comment = frm['comment.'+poolNo].value; 153 poolInfo.ebVolumeExtra = POOL_DATA[poolNo].ebVolumeExtra; 151 154 poolInfo.libs = []; 152 155 poolInfo.excluded = []; … … 161 164 tmp.id = lib.id; 162 165 tmp.name = lib.name; 163 tmp.volume = Math.min(lib.volume, lib.maxVolume); // Never submit more than max volume164 tmp.eb = Math.max(0, lib.eb); // Never submit negative EB volumes!166 tmp.volume = lib.actualVolume; 167 tmp.eb = lib.actualEb; 165 168 tmp.mixFactor = lib.mixFactor; 166 169 tmp.comment = lib.comment; … … 359 362 { 360 363 PoolMix.calculateLibVolume(lib, TARGET_MOLARITY_IN_POOL, targetVolumePerLib, mixingStrategy); 364 PoolMix.calculateEbVolume(lib, TARGET_MOLARITY_IN_POOL, targetVolumePerLib, mixingStrategy); 361 365 } 362 366 } … … 387 391 if (lib.molarity != null) 388 392 { 389 if (lib.volume > lib.maxVolume) 390 { 391 remarks[remarks.length] = 'Low molarity'; 393 if (lib.volume != lib.actualVolume) 394 { 395 if (lib.volume > lib.remainingVolume) 396 { 397 remarks[remarks.length] = 'Low quantity'; 398 } 399 else 400 { 401 remarks[remarks.length] = 'Low molarity'; 402 } 392 403 } 393 404 … … 397 408 } 398 409 399 if (lib.mixFactor > 1 .001)410 if (lib.mixFactor > 1) 400 411 { 401 412 // Larger mix than default 402 remarks[remarks.length] = 'Use ' + Numbers.formatNumber(lib. volume+lib.eb, 1, 'µl') + ' in pool';413 remarks[remarks.length] = 'Use ' + Numbers.formatNumber(lib.actualVolume+lib.actualEb, 1, 'µl') + ' in pool'; 403 414 } 404 415 … … 435 446 } 436 447 437 // Calculate EB438 PoolMix.calculateEbForLibs(libs, TARGET_MOLARITY_IN_POOL, targetVolumePerLib, mixingStrategy);439 440 448 // Calculate final pool volumes, molarity, etc. 441 var poolInfo = PoolMix.calculateFinalPoolInfo(libs, mixingStrategy); 449 var poolInfo = PoolMix.calculateFinalPoolInfo(libs, TARGET_MOLARITY_IN_POOL, targetVolumePerLib, mixingStrategy); 450 POOL_DATA[poolNo] = poolInfo; 442 451 443 452 // Make remarks for each lib … … 449 458 450 459 var warnMsg = null; 451 if (poolInfo.eb < 0)460 if (poolInfo.ebVolumeExtra < 0) 452 461 { 453 462 warnMsg = 'Too many libs with low molarity'; … … 461 470 if (mixingStrategy == 'dynamic') 462 471 { 463 poolData += ' • <span class="pool-eb">'+Numbers.formatNumber(poolInfo.eb FinalMix, 1, 'µl')+'</span>';472 poolData += ' • <span class="pool-eb">'+Numbers.formatNumber(poolInfo.ebVolumeExtra, 1, 'µl')+'</span>'; 464 473 } 465 474 if (warnMsg) … … 517 526 cls += ' flagged'; 518 527 } 519 if (!lib.flag && lib. volume > lib.maxVolume)528 if (!lib.flag && lib.actualVolume < lib.volume) 520 529 { 521 530 cls += ' low-volume'; … … 549 558 if (!lib.excludeFromPool) 550 559 { 551 mark = (lib.volume > lib. maxVolume) ? '*' : '';560 mark = (lib.volume > lib.actualVolume) ? '*' : ''; 552 561 text += '<div>'; 553 562 text += '<span class="volume">'+(isFinite(lib.volume) ? Numbers.formatNumber(lib.volume*mixFactor, 1, 'µl'+mark) : '∞')+'</span>'; 554 if (painter.mixingStrategy == 'fixed' || lib.mixFactor > 1 .001)563 if (painter.mixingStrategy == 'fixed' || lib.mixFactor > 1) 555 564 { 556 565 text += '<span class="eb">'+(isFinite(lib.eb) ? Numbers.formatNumber(lib.eb*mixFactor, 1, 'µl') : '-∞')+'</span>'; -
extensions/net.sf.basedb.reggie/trunk/resources/libprep/pool_protocol2.jsp
r2067 r2140 154 154 // Calculate some pool quantities 155 155 pool.volume = 1000 * pool.originalQuantity / pool.conc; 156 157 PoolMix.calculateEbForLibs(pool.libraries, pool.molarity, pool.targetVolumePerLib, pool.mixingStrategy); 158 pool.extra = PoolMix.calculateFinalPoolInfo(pool.libraries, pool.mixingStrategy); 159 160 for (var j = 0; j < pool.libraries.length; j++) 161 { 162 checkAndPreProcessLibrary(pool.libraries[j], pool, POOL_CURRENT_SCHEMA, POOL_CURRENT_BARCODE_VARIANT, '<%=view%>'); 163 } 164 156 157 for (var libNo = 0; libNo < pool.libraries.length; libNo++) 158 { 159 var lib = pool.libraries[libNo]; 160 PoolMix.calculateLibVolumeForProtocol(lib, pool.targetPoolMolarity, pool.targetVolumePerLib, pool.mixingStrategy, true); 161 PoolMix.calculateEbVolume(lib, pool.targetPoolMolarity, pool.targetVolumePerLib, pool.mixingStrategy); 162 checkAndPreProcessLibrary(lib, pool, POOL_CURRENT_SCHEMA, POOL_CURRENT_BARCODE_VARIANT, '<%=view%>'); 163 } 164 165 pool.extra = PoolMix.calculateFinalPoolInfo(pool.libraries, pool.targetPoolMolarity, pool.targetVolumePerLib, pool.mixingStrategy); 165 166 } 166 167 … … 213 214 } 214 215 215 if (lib.mixFactor > 1 .001)216 if (lib.mixFactor > 1) 216 217 { 217 218 // Larger mix than default 218 219 if (view != 'plate') 219 220 { 220 remarks[remarks.length] = '<span class="mix-remark">Mix <span class="volume">'+Numbers.formatNumber(lib. volume*lib.mixFactor, 1) + '</span>+<span class="eb">' + Numbers.formatNumber(lib.eb*lib.mixFactor, 1)+'µl</span></span>';221 } 222 remarks[remarks.length] = 'Use <b>' + Numbers.formatNumber(lib. volume+lib.eb, 1) + 'µl</b> in pool';221 remarks[remarks.length] = '<span class="mix-remark">Mix <span class="volume">'+Numbers.formatNumber(lib.actualVolume*lib.mixFactor, 1) + '</span>+<span class="eb">' + Numbers.formatNumber(lib.actualEb*lib.mixFactor, 1)+'µl</span></span>'; 222 } 223 remarks[remarks.length] = 'Use <b>' + Numbers.formatNumber(lib.actualVolume+lib.actualEb, 1) + 'µl</b> in pool'; 223 224 } 224 225 … … 261 262 var well = lib.bioWell; 262 263 264 var tr = document.createElement('tr'); 263 265 if (POOL_CURRENT_SCHEMA) 264 266 { 265 267 wellIndex = createMissingRows(tbody, wellsInPool, wellIndex, well, barcodeVariant); 266 } 267 268 var tr = document.createElement('tr'); 269 tr.className = well.column % 2 == 0 ? "evencol" : "oddcol"; 268 tr.className = well.column % 2 == 0 ? "evencol" : "oddcol"; 269 } 270 else 271 { 272 tr.className = 'evencol'; 273 } 270 274 271 275 if (barcodeVariant) … … 279 283 280 284 addColumn(tr, 'lib', lib.name); 281 addColumn(tr, 'remain', Numbers.formatNumber((lib.remaining Quantity+lib.usedQuantity)*1000, 2));285 addColumn(tr, 'remain', Numbers.formatNumber((lib.remainingVolume), 1)); 282 286 addColumn(tr, 'molarity', Numbers.formatNumber(lib.molarity, 2)); 283 287 <% … … 296 300 %> 297 301 var mixFactor = lib.mixFactor || 1.0; 298 addColumn(tr, 'volume', mixFactor > 1.0 ? '—' : Numbers.formatNumber(lib. volume*mixFactor, 1));299 addColumn(tr, 'eb', pool.mixingStrategy == 'dynamic' || mixFactor > 1.0 01 ? '—' : Numbers.formatNumber(lib.eb*mixFactor, 1));302 addColumn(tr, 'volume', mixFactor > 1.0 ? '—' : Numbers.formatNumber(lib.actualVolume, 1)); 303 addColumn(tr, 'eb', pool.mixingStrategy == 'dynamic' || mixFactor > 1.0 ? '—' : Numbers.formatNumber(lib.actualEb, 1)); 300 304 addColumn(tr, "remarks", lib.remarks.join('; ')); 301 305 tbody.appendChild(tr); … … 312 316 poolData += '</div>'; 313 317 setInnerHTML('molarity.'+pool.id, poolData); 314 setInnerHTML('eb-volume.'+pool.id, Numbers.formatNumber( pool.extra.ebFinalMix, 1));318 setInnerHTML('eb-volume.'+pool.id, Numbers.formatNumber(Math.max(0, pool.extra.ebVolumeExtra), 1)); 315 319 Main.show('pool.'+pool.id); 316 320 } … … 382 386 if (pool.mixingStrategy == 'dynamic') 383 387 { 384 poolData += ' • <span class="pool-eb">'+Numbers.formatNumber(pool.extra.eb FinalMix, 1, 'µl')+'</span>';388 poolData += ' • <span class="pool-eb">'+Numbers.formatNumber(pool.extra.ebVolumeExtra, 1, 'µl')+'</span>'; 385 389 } 386 390 poolData += '<div class="comments">'+pool.comments+'</div>'; … … 418 422 var i = name.indexOf('.m'); 419 423 text += '<div class="lib">'+name.substring(0, i)+'.<br> '+name.substring(i)+'</div>'; 420 text += '<div><span class="volume">'+Numbers.formatNumber(lib. volume*mixFactor, 1)+'µl</span>';424 text += '<div><span class="volume">'+Numbers.formatNumber(lib.actualVolume*mixFactor, 1)+'µl</span>'; 421 425 if (painter.mixingStrategy == 'fixed' || lib.mixFactor > 1.001) 422 426 { 423 text += '<span class="eb">'+Numbers.formatNumber(lib. eb*mixFactor, 1)+'µl</span>';427 text += '<span class="eb">'+Numbers.formatNumber(lib.actualEb*mixFactor, 1)+'µl</span>'; 424 428 } 425 429 else … … 746 750 <tr> 747 751 <th class="lib">Library</th> 748 <th>( ng)</th>752 <th>(µl)</th> 749 753 <th>(nM)</th> 750 754 <th class="workplate">plate</th> -
extensions/net.sf.basedb.reggie/trunk/resources/libprep/pools.js
r2137 r2140 294 294 295 295 /** 296 Calculate the volume of a lib to take for a pool given the 296 Checks if v1 is less than v2 within the given accuracy 297 Eg. v1+accuracy <= v2 298 */ 299 pm.lessThan = function(v1, v2, accuracy) 300 { 301 return v1 + accuracy < v2; 302 } 303 304 /** 305 Calculate the volume of a lib to use for a pool given the 297 306 target molarity for the pool and average volume for each lib 298 in the pool. The volume is affect by two limits: 299 300 1. It may not be lower than LIMIT_FOR_EXTRA_LARGE_MIX. In this case 301 a larger mix is made and only half is used. 302 303 2. It may not be higher than AVAILABLE_VOLUME or AVAILABLE_VOLUME_AFTER_SPEEDVAC. 307 in the pool. This method calculates two different volumes: 308 309 lib.volume = The theoretical volume needed to reach the same 310 amount of DNA as the target molarity and volume suggests 311 312 lib.actualVolume: The actual volume that can be used due to 313 remaining quantity, lib molarity and mixing strategy 304 314 305 315 The volume is rounded to one decimal in µl. 316 306 317 */ 307 318 pm.calculateLibVolume = function(lib, targetMolarity, targetVolume, mixingStrategy) 308 319 { 309 var maxVolume = lib.remainingVolume;310 if (mixingStrategy == 'fixed' && maxVolume > targetVolume)311 {312 maxVolume = targetVolume;313 }314 320 var volume = pm.round(targetVolume * targetMolarity / lib.molarity); 315 321 var mixFactor = 1; 316 if (volume < LIMIT_FOR_EXTRA_LARGE_MIX) 322 323 if (pm.lessThan(volume, LIMIT_FOR_EXTRA_LARGE_MIX, 0.05)) 317 324 { 318 325 mixFactor = 2; … … 322 329 } 323 330 324 lib.maxVolume = maxVolume;331 // This is the theoretical volume that should be used... 325 332 lib.volume = volume; 333 lib.eb = null; 326 334 lib.mixFactor = mixFactor; 327 lib.eb = null; 328 return volume; 329 } 330 331 /** 332 Calculate the amount of EB to mix with each of the libs. If mixing 333 strategy is 'fixed' all libraries are mixed to the target volume, 334 otherwise a dynamic strategy that prioritize the final pool molarity 335 is used: 336 337 1. The total amount of EB needed to achive the target molarity 338 in the pool is calculated. 339 340 2. Libs with a mixFactor > 1 are always mixed to the given target 341 molarity since the saved lib should be standardized 342 343 3. The remaining EB volume is equally split among the rest of the 344 libs. To avoid rounding errors for the pool as a total the 345 volume is rounded down and then any remaining EB is added to 346 the last lib. 347 */ 348 pm.calculateEbForLibs = function(libs, targetMolarity, targetVolume, mixingStrategy) 349 { 350 if (mixingStrategy == 'fixed') 351 { 352 // Fixed strategy 353 // All libs are mixed with EB to target volume 354 for (var libNo = 0; libNo < libs.length; libNo++) 355 { 356 var lib = libs[libNo]; 357 lib.eb = targetVolume - lib.volume; 358 } 335 336 // However, reality has limitations due to remaining volume, mixing strategy, etc. 337 // Check what volume that can actually be used 338 if (mixingStrategy == 'fixed' || lib.mixFactor > 1) 339 { 340 // Do not use more than target volume or remaining volume 341 volume = Math.min(volume, targetVolume, lib.remainingVolume); 359 342 } 360 343 else 361 344 { 362 // Dynamic strategy 363 // First, calculate total volume of all libs 364 // and their contribution to the total amount of DNA in the pool 365 var totalLibVolume = 0; 366 var totalLibAmount = 0; 367 var fixedEbVolume = 0; 368 var fixedLibs = 0; 369 for (var libNo = 0; libNo < libs.length; libNo++) 370 { 371 var lib = libs[libNo]; 372 var vol = lib.maxVolume < lib.volume ? lib.maxVolume : lib.volume; 373 totalLibVolume += vol; 374 totalLibAmount += vol * lib.molarity; 375 376 // Always mix to target molarity when doing extra large mix 377 if (lib.mixFactor > 1) 378 { 379 var eb = targetVolume - lib.volume; 380 fixedEbVolume += eb; 381 lib.eb = eb; 382 fixedLibs++; 383 } 384 } 385 386 387 // Calculate the total volume needed to get to the 388 // target molarity for the pooled libs 389 // Round all summarized values to avoid precision problems (eg. 4.0 --> 3.999999998) 390 var totalPoolVolume = pm.round(totalLibAmount / targetMolarity); 391 totalLibVolume = pm.round(totalLibVolume); 392 fixedEbVolume = pm.round(fixedEbVolume); 393 var totalEbVolume = pm.round(totalPoolVolume - totalLibVolume - fixedEbVolume); 394 395 // Divide EB volume among the libs (rounded to 1 decimal) 396 var ebPerLib = pm.floor(totalEbVolume / (libs.length - fixedLibs), 1); 397 var usedEb = 0; 398 var adjustableLib; 399 for (var libNo = 0; libNo < libs.length; libNo++) 400 { 401 var lib = libs[libNo]; 402 if (!lib.mixFactor || lib.mixFactor == 1) 403 { 404 lib.eb = ebPerLib; 405 usedEb += ebPerLib; 406 adjustableLib = lib; 407 } 408 } 409 410 usedEb = pm.round(usedEb); 411 412 // If the used EB doesn't add up to the total amount needed (due to rounding) 413 // add the extra amount to the last lib 414 if (Math.abs(totalEbVolume - usedEb) >= 0.05 && adjustableLib) 415 { 416 adjustableLib.eb += totalEbVolume - usedEb; 417 } 418 } 419 420 } 421 422 pm.calculateFinalPoolInfo = function(libs, mixingStrategy) 423 { 424 var info = {}; 425 345 volume = Math.min(volume, lib.remainingVolume); 346 } 347 lib.actualVolume = volume; 348 } 349 350 /** 351 Same as above method except that we already know the mixFactor and actualVolume of 352 the lib since that has already been saved to the database. 353 */ 354 pm.calculateLibVolumeForProtocol = function(lib, targetMolarity, targetVolume, mixingStrategy) 355 { 356 if (lib.mixFactor > 1) 357 { 358 lib.volume = pm.ceil(lib.mixFactor * targetVolume * targetMolarity / lib.molarity) / lib.mixFactor; 359 } 360 else 361 { 362 lib.volume = pm.round(targetVolume * targetMolarity / lib.molarity); 363 } 364 } 365 366 367 /** 368 Calculate the volume of EB to mix with a lib. 369 370 The volume is rounded to one decimal in µl. 371 */ 372 pm.calculateEbVolume = function(lib, targetMolarity, targetVolume, mixingStrategy) 373 { 374 var eb = 0; 375 if (mixingStrategy == 'fixed' || lib.mixFactor > 1) 376 { 377 eb = targetVolume - lib.volume; 378 } 379 380 // This is the theoretical volume that should be used... 381 lib.eb = eb; 382 383 // However, reality has limitations due to remaining volume, mixing strategy, etc. 384 // Check what volume that can actually be used 385 if (mixingStrategy == 'fixed' || lib.mixFactor > 1) 386 { 387 if (pm.lessThan(lib.molarity, targetMolarity, 0.01)) 388 { 389 // Do not dilute if molarity is lower than target molarity 390 eb = 0; 391 } 392 else if (pm.lessThan(lib.actualVolume, lib.volume, 0.05)) 393 { 394 // Reduce EB by the same factor as we have to reduce the volume 395 // so the final molarity is still 396 eb = pm.round(eb * lib.actualVolume / lib.volume); 397 } 398 } 399 lib.actualEb = eb; 400 } 401 402 403 404 /** 405 Summarize information for the pool. This will calculate the following and 406 return as an object: 407 408 libVolume: Total volume of libs in the pool (µl) 409 libAmount: Total amount of libs in the pool (nano-mol) 410 ebVolumeFromLibs: Total EB volume from mixed directly with libs 411 ebVolumeExtra: Extra EB to add to the pool (dynamic mixing) 412 molarity: The final pool molarity after mixing everything 413 */ 414 pm.calculateFinalPoolInfo = function(libs, targetMolarity, targetVolume, mixingStrategy) 415 { 426 416 var libVolume = 0; 427 417 var libAmount = 0; 428 var ebVolume = 0;429 var ebFinalMix = 0;418 var ebVolumeFromLibs = 0; 419 430 420 for (var libNo = 0; libNo < libs.length; libNo++) 431 421 { 432 422 var lib = libs[libNo]; 433 var vol = lib.maxVolume < lib.volume ? lib.maxVolume : lib.volume; 434 libVolume += vol; 435 ebVolume += lib.eb; 436 if (mixingStrategy == 'dynamic' && (!lib.mixFactor || lib.mixFactor == 1)) 437 { 438 ebFinalMix += lib.eb; 439 } 440 libAmount += vol * lib.molarity; 441 } 442 443 info.volume = libVolume; 444 info.amount = libAmount; 445 info.eb = ebVolume; 446 info.ebFinalMix = ebFinalMix; 447 if (ebVolume < 0) 448 { 449 info.totalVolume = libVolume; 423 424 var volume = lib.actualVolume; 425 var eb = lib.actualEb; 426 427 libVolume += volume; 428 ebVolumeFromLibs += eb; 429 libAmount += volume * lib.molarity; 430 } 431 432 var info = {}; 433 info.libVolume = libVolume; 434 info.libAmount = libAmount; 435 info.ebVolumeFromLibs = ebVolumeFromLibs; 436 437 // Calculate extra EB and total pool volume 438 if (mixingStrategy == 'dynamic') 439 { 440 // Use the target molarity to calculate the total volume 441 var targetVolume = pm.round(libAmount / targetMolarity); 442 info.ebVolumeExtra = pm.round(targetVolume - info.libVolume - info.ebVolumeFromLibs); 443 if (info.ebVolumeExtra < 0) 444 { 445 info.totalVolume = info.libVolume + info.ebVolumeFromLibs; 446 } 447 else 448 { 449 info.totalVolume = targetVolume; 450 } 450 451 } 451 452 else 452 453 { 453 info.totalVolume = libVolume + ebVolume; 454 } 455 info.molarity = libAmount / info.totalVolume; 456 454 // No extra EB 455 info.ebVolumeExtra = 0; 456 info.totalVolume = info.libVolume + info.ebVolumeFromLibs; 457 } 458 // Calcualate the final molarity (which may be different that target due to rounding) 459 info.molarity = info.libAmount / info.totalVolume; 460 457 461 return info; 458 462 } -
extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/dao/Annotationtype.java
r2134 r2140 595 595 public static final Annotationtype POOL_TARGET_VOLUME_PER_LIB = 596 596 new Annotationtype("PoolTargetVolumePerLib", Type.FLOAT, Item.EXTRACT); 597 598 /** 599 The "PoolTargetMolarity" annotation, used for extracts (PooledLibrary). 600 Store the admin-defined setting for target molarity used when designing 601 the pool. The actual molarity may different due to limitations implied by 602 library concentration and rounding. 603 @since 2.14 604 */ 605 public static final Annotationtype POOL_TARGET_MOLARITY = 606 new Annotationtype("PoolTargetMolarity", Type.FLOAT, Item.EXTRACT); 597 607 598 608 /** -
extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/servlet/InstallServlet.java
r2134 r2140 277 277 jsonChecks.add(checkAnnotationType(dc, Annotationtype.POOL_MOLARITY, 1, null, effectiveOptions, createIfMissing)); 278 278 jsonChecks.add(checkAnnotationType(dc, Annotationtype.POOL_TARGET_VOLUME_PER_LIB, 1, null, effectiveOptions, createIfMissing)); 279 jsonChecks.add(checkAnnotationType(dc, Annotationtype.POOL_TARGET_MOLARITY, 1, null, effectiveOptions, createIfMissing)); 279 280 jsonChecks.add(checkAnnotationType(dc, Annotationtype.POOL_MIXING_STRATEGY, 1, 280 281 new ValueOptions(PooledLibrary.MIXING_STRATEGY_FIXED, PooledLibrary.MIXING_STRATEGY_DYNAMIC), … … 383 384 jsonChecks.add(checkAnnotationTypeCategory(dc, Subtype.POOLED_LIBRARY, createIfMissing, 384 385 Annotationtype.POOL_MOLARITY, Annotationtype.POOL_CONC, Annotationtype.POOL_TARGET_VOLUME_PER_LIB, 386 Annotationtype.POOL_TARGET_MOLARITY, 385 387 Annotationtype.POOL_MIXING_STRATEGY, Annotationtype.POOL_DATE, Annotationtype.OPERATOR, 386 388 Annotationtype.FLAG, Annotationtype.AUTO_PROCESSING)); -
extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/servlet/PoolServlet.java
r2137 r2140 316 316 if (targetVolumePerLib == null) targetVolumePerLib = DEFAULT_TARGET_VOLUME_IN_POOL_PER_LIB; 317 317 pool.setAnnotation("targetVolumePerLib", targetVolumePerLib); 318 Float targetPoolMolarity = (Float)Annotationtype.POOL_TARGET_MOLARITY.getAnnotationValue(dc, pool.getExtract()); 319 if (targetPoolMolarity == null) targetPoolMolarity = TARGET_MOLARITY_IN_POOL; 320 pool.setAnnotation("targetPoolMolarity", targetPoolMolarity); 318 321 String mixingStrategy = (String)Annotationtype.POOL_MIXING_STRATEGY.getAnnotationValue(dc, pool.getExtract()); 319 322 if (mixingStrategy == null) mixingStrategy = PooledLibrary.MIXING_STRATEGY_FIXED; … … 326 329 327 330 JSONObject poolInfo = new JSONObject(); 328 poolInfo.put("targetMolarity", TARGET_MOLARITY_IN_POOL);329 331 poolInfo.put("extraLargeMixFactor", EXTRA_LARGE_MIX_FACTOR); 330 332 poolInfo.put("limitForExtraLargeMix", LIMIT_FOR_EXTRA_LARGE_MIX); … … 374 376 JSONArray jsonFlagged = (JSONArray)jsonReq.get("flagged"); 375 377 Number targetVolumeInPoolPerLib = (Number)jsonReq.get("targetVolumeInPoolPerLib"); 378 Number targetPoolMolarity = (Number)jsonReq.get("targetPoolMolarity"); 376 379 String mixingStrategy = (String)jsonReq.get("mixingStrategy"); 377 380 … … 394 397 pool.setDescription((String)jsonPool.get("comment")); 395 398 Annotationtype.POOL_TARGET_VOLUME_PER_LIB.setAnnotationValue(dc, pool, targetVolumeInPoolPerLib.floatValue()); 399 Annotationtype.POOL_TARGET_MOLARITY.setAnnotationValue(dc, pool, targetPoolMolarity.floatValue()); 396 400 Annotationtype.POOL_MIXING_STRATEGY.setAnnotationValue(dc, pool, mixingStrategy); 397 401 … … 399 403 400 404 // Total pool quantities 401 float poolVolume = 0f; // volume in pool (µl)405 float poolVolume = ((Number)jsonPool.get("ebVolumeExtra")).floatValue(); // volume in pool (µl) 402 406 float poolQuantity = 0f; // quantity of DNA in pool (µg) 403 407 float poolAmount = 0f; // Amount of DNA in pool (nano-mole) … … 633 637 // Load remaining quantity of the lib 634 638 Float remain = libEx.getRemainingQuantity(); 635 lib.setAnnotation("remainingQuantity", remain);636 if (remain != null && (originalConc != null || speedVacConc != null))637 {638 // Remaining volume in µl639 Float conc = speedVacConc == null ? originalConc : speedVacConc;640 lib.setAnnotation("remainingVolume", 1000 * remain / conc);641 }642 639 643 640 if (pool != null) … … 649 646 Float usedVolumeForMix = 1000 * usedQuantity / usedConc; 650 647 651 lib.setAnnotation("volume", usedVolumeForMix); 648 // Add the used quantity back since we want the remaining quantity *before* pooling 649 if (remain != null) remain += usedQuantity; 650 651 // The actual volume used when pooling 652 lib.setAnnotation("actualVolume", usedVolumeForMix); 652 653 653 654 // Check if '.dil' exists … … 661 662 Extract dil = result.get(0); 662 663 Float dilQuantity = dil.getOriginalQuantity(); 663 //Float dilConc = (Float)Annotationtype.POOL_CONC.getAnnotationValue(dc, dil);664 664 lib.setAnnotation("mixFactor", (dilQuantity + usedQuantity) / usedQuantity); 665 665 } 666 666 667 667 lib.setAnnotation("dils", result.size()); 668 } 669 670 lib.setAnnotation("remainingQuantity", remain); 671 if (remain != null && (originalConc != null || speedVacConc != null)) 672 { 673 // Remaining volume in µl 674 Float conc = speedVacConc == null ? originalConc : speedVacConc; 675 lib.setAnnotation("remainingVolume", 1000 * remain / conc); 668 676 } 669 677 }
Note: See TracChangeset
for help on using the changeset viewer.