Changeset 2186


Ignore:
Timestamp:
Jan 10, 2014, 12:56:24 PM (8 years ago)
Author:
Nicklas Nordborg
Message:

References #555: Specify amount to use from *.dil items in pool

The volume to use in the pool can now be set by selecting the wells and clicking the 'Separate mix volume' button.

As a side-effect the mix factor is now calculated dynamically so that around 2µl is used from the original lib. The previous implementation with a fixed mix factor could still yield lower than 1µl for libraries with very high contentration (>20nM).

Location:
extensions/net.sf.basedb.reggie/trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • extensions/net.sf.basedb.reggie/trunk/resources/libprep/create_pools.jsp

    r2184 r2186  
    4343var LIMIT_FOR_AUTO_EXCLUDE = 0.25;
    4444var LIMIT_FOR_EXTRA_LARGE_MIX;
    45 var EXTRA_LARGE_MIX_FACTOR;
     45var MAX_TARGET_VOLUME = 10;
     46var MIN_TARGET_VOLUME = 2;
    4647
    4748function init()
     
    151152    poolInfo.targetPoolMolarity = TARGET_MOLARITY_IN_POOL;
    152153    poolInfo.targetVolumeInPoolPerLib = parseFloat(frm['target_volume.'+poolNo].value);
    153     poolInfo.mixingStrategy = Forms.getCheckedRadio(frm['mixing_strategy.'+poolNo]).value;
     154    var mixingStrategy = Forms.getCheckedRadio(frm['mixing_strategy.'+poolNo]).value;
     155    poolInfo.mixingStrategy = mixingStrategy;
    154156    poolInfo.comment = frm['comment.'+poolNo].value;
    155157    poolInfo.ebVolumeExtra = POOL_DATA[poolNo].ebVolumeExtra;
     
    170172        tmp.eb = lib.actualEb;
    171173        tmp.mixFactor = lib.mixFactor;
     174        if (lib.mixFactor > 1 && lib.targetVolume && mixingStrategy == 'dynamic')
     175        {
     176          tmp.targetVolume = lib.targetVolume;
     177        }
    172178        tmp.comment = lib.comment;
    173179       
     
    270276  var poolInfo = response.poolInfo;
    271277  TARGET_MOLARITY_IN_POOL = poolInfo.targetMolarity;
    272   EXTRA_LARGE_MIX_FACTOR = poolInfo.extraLargeMixFactor;
    273278  LIMIT_FOR_EXTRA_LARGE_MIX = poolInfo.limitForExtraLargeMix;
    274279 
    275   //setInnerHTML('pool_schema', schema.name);
    276   //setInnerHTML('barcode_variant', barcodeVariant.name);
    277280  setInnerHTML('target_molarity', Numbers.formatNumber(TARGET_MOLARITY_IN_POOL, 1, ' nM'));
    278281
     
    348351    html += '<td><input type="text" style="width: 4em;" name="target_volume.'+poolNo+'" value="'+targetVolumePerLib+'"';
    349352    html += ' onblur="targetVolumeOnBlur(event)" onkeypress="doOnEnter(event, targetVolumeOnBlur); return Numbers.numberOnly(event)">';
    350     html += 'µl (2--10)</td>';
     353    html += 'µl ('+MIN_TARGET_VOLUME+'--'+MAX_TARGET_VOLUME+')</td>';
    351354    html += '<td id="target_volume.'+poolNo+'.status"></td></tr>';
    352355    html += '<tr><td class="prompt">Mixing strategy</td>';
     
    382385 
    383386  targetVolumePerLibIsValid[poolNo] = false;
    384   if (targetVolumePerLib < 2 || targetVolumePerLib > 10)
    385   {
    386     setInputStatus('target_volume.'+poolNo, 'Must be between 2 and 10µl', 'invalid');
     387  if (targetVolumePerLib < MIN_TARGET_VOLUME || targetVolumePerLib > MAX_TARGET_VOLUME)
     388  {
     389    setInputStatus('target_volume.'+poolNo, 'Must be between '+MIN_TARGET_VOLUME+' and '+MAX_TARGET_VOLUME+'µl', 'invalid');
    387390    return;
    388391  }
     
    510513    }
    511514   
    512     WellPainter.mixingStrategy = mixingStrategy;
    513515    Plate.paint(wells);
    514516
     
    622624        text += '<div>';
    623625        text += '<span class="volume">'+(isFinite(lib.volume) ? Numbers.formatNumber(lib.volume*mixFactor, 1, 'µl'+mark) : '∞')+'</span>';
    624         if (painter.mixingStrategy == 'fixed' || lib.mixFactor > 1)
     626        if (lib.mixingStrategy == 'fixed' || lib.mixFactor > 1)
    625627        {
    626628          text += '<span class="eb">'+(isFinite(lib.eb) ? Numbers.formatNumber(lib.eb*mixFactor, 1, 'µl') : '-∞')+'</span>';
     
    696698 
    697699  updatePoolData();
    698   Plate.paint(Plate.getWells());
    699700}
    700701
     
    724725 
    725726  updatePoolData();
    726   Plate.paint(Plate.getWells());
    727727}
    728728
     
    756756  }
    757757 
    758   Plate.paint(wells);
     758  updatePoolData();
    759759}
    760760
     
    805805    well.selected = false;
    806806  }
    807   Plate.paint(wells);
     807 
     808  updatePoolData();
     809}
     810
     811//Set target volume on the selected wells
     812var lastTargetVolume = null;
     813function setTargetVolume(targetVolume)
     814{
     815  var wells = Plate.getSelected();
     816 
     817  if (targetVolume == undefined)
     818  {
     819    if (wells.length == 0)
     820    {
     821      alert('No wells have been selected');
     822      return;
     823    }
     824   
     825    var count = 0;
     826    for (var i = 0; i < wells.length; i++)
     827    {
     828      var well = wells[i];
     829      if (well.extract && well.extract.mixFactor > 1)
     830      {
     831        if (well.extract.targetVolume) targetVolume = well.extract.targetVolume;
     832        count++;
     833      }
     834    }
     835   
     836    if (count == 0)
     837    {
     838      alert('Only empty or dynamic-mixed wells have been selected');
     839      return;
     840    }
     841   
     842    targetVolume = parseFloat(prompt('Volume to use in pool ('+LIMIT_FOR_EXTRA_LARGE_MIX+'--'+MAX_TARGET_VOLUME+' µl)', targetVolume || lastTargetVolume));
     843    if (isNaN(targetVolume))
     844    {
     845      targetVolume = null;
     846    }
     847    else if (targetVolume > MAX_TARGET_VOLUME)
     848    {
     849      targetVolume = MAX_TARGET_VOLUME;
     850    }
     851    else if (targetVolume < LIMIT_FOR_EXTRA_LARGE_MIX)
     852    {
     853      targetVolume = LIMIT_FOR_EXTRA_LARGE_MIX
     854    }
     855  }
     856 
     857  lastTargetVolume = targetVolume;
     858 
     859  if (targetVolume == '') targetVolume = null;
     860  var frm = document.forms['reggie'];
     861  for (var i = 0; i < wells.length; i++)
     862  {
     863    var well = wells[i];
     864    if (well.extract)
     865    {
     866      var lib = well.extract;
     867      lib.targetVolume = targetVolume;
     868      var poolNo = Plate.poolSchema.getPoolNumForColumn(lib.bioWell.column);
     869     
     870      var targetVolumePerLib = parseFloat(frm['target_volume.'+poolNo].value);
     871      var mixingStrategy = Forms.getCheckedRadio(frm['mixing_strategy.'+poolNo]).value;
     872      PoolMix.calculateEbVolume(lib, TARGET_MOLARITY_IN_POOL, targetVolumePerLib, mixingStrategy);
     873    }
     874    well.selected = false;
     875  }
     876 
     877  updatePoolData();
    808878}
    809879
     
    10421112          onclick="includeSelected()"
    10431113          tooltip="Include the selected libraries in the pool"
     1114        />
     1115        <tbl:button
     1116          title="Separate mix volume&hellip;"
     1117          image="<%=home+"/images/specimen.png"%>"
     1118          onclick="setTargetVolume()"
     1119          tooltip="Set volume to use in the pool for separately mixed libraries (dynamic mixing only)"
    10441120        />
    10451121        <tbl:button
  • extensions/net.sf.basedb.reggie/trunk/resources/libprep/pool_protocol2.jsp

    r2184 r2186  
    382382      var pool = pools[poolNo];
    383383      var realPoolNo = schema.getPoolNumForColumn(pool.libraries[0].bioWell.column);
    384       WellPainter.mixingStrategy = pool.mixingStrategy;
    385384      Plate.paint(Plate.getPool(realPoolNo));
    386385     
     
    428427        text += '<div class="lib">'+name.substring(0, i)+'.<br>&nbsp;'+name.substring(i)+'</div>';
    429428        text += '<div><span class="volume">'+Numbers.formatNumber(lib.actualVolume*mixFactor, 1)+'µl</span>';
    430         if (painter.mixingStrategy == 'fixed' || lib.mixFactor > 1.001)
     429        if (lib.mixingStrategy == 'fixed' || lib.mixFactor > 1)
    431430        {
    432431          text += '<span class="eb">'+Numbers.formatNumber(lib.actualEb*mixFactor, 1)+'µl</span>';
  • extensions/net.sf.basedb.reggie/trunk/resources/libprep/pools.js

    r2140 r2186  
    323323    if (pm.lessThan(volume, LIMIT_FOR_EXTRA_LARGE_MIX, 0.05))
    324324    {
    325       mixFactor = 2;
    326       // Re-calculate the volume to get the rounding correct (eg. to avoid dubling rounding errors)
    327       // round UP this time to avoid storing something that is less than 2nM
    328       volume = pm.ceil(mixFactor * targetVolume * targetMolarity / lib.molarity) / mixFactor;
     325      // Mix 'dil' so that we take about 2 times the minimal limit
     326      mixFactor = Math.max(2 * LIMIT_FOR_EXTRA_LARGE_MIX / volume);
     327      // Re-calculate the volume to get the rounding correct (eg. to avoid doubling rounding errors)
     328      volume = pm.round(mixFactor * targetVolume * targetMolarity / lib.molarity) / mixFactor;
    329329    }
    330330   
     
    336336    // However, reality has limitations due to remaining volume, mixing strategy, etc.
    337337    // Check what volume that can actually be used
    338     if (mixingStrategy == 'fixed' || lib.mixFactor > 1)
     338    if (mixingStrategy == 'fixed')
    339339    {
    340340      // Do not use more than target volume or remaining volume
     
    356356    if (lib.mixFactor > 1)
    357357    {
    358       lib.volume = pm.ceil(lib.mixFactor * targetVolume * targetMolarity / lib.molarity) / lib.mixFactor;
     358      lib.volume = pm.round(lib.mixFactor * targetVolume * targetMolarity / lib.molarity) / lib.mixFactor;
    359359    }
    360360    else
     
    373373  {
    374374    var eb = 0;
    375     if (mixingStrategy == 'fixed' || lib.mixFactor > 1)
     375    if (mixingStrategy == 'fixed')
    376376    {
    377377      eb = targetVolume - lib.volume;
     378    }
     379    else if (lib.mixFactor > 1)
     380    {
     381      eb = (lib.targetVolume ? lib.targetVolume : targetVolume) - lib.volume;
    378382    }
    379383   
    380384    // This is the theoretical volume that should be used...
    381385    lib.eb = eb;
     386    lib.mixingStrategy = mixingStrategy;
    382387   
    383388    // However, reality has limitations due to remaining volume, mixing strategy, etc.
  • extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/servlet/PoolServlet.java

    r2184 r2186  
    468468              dil.setItemSubtype(libraryType);
    469469              dil.setName(lib.getName()+".dil");
     470              Number targetVolume = (Number)jsonLib.get("targetVolume");
     471              if (targetVolume != null)
     472              {
     473                Annotationtype.POOL_TARGET_VOLUME_PER_LIB.setAnnotationValue(dc, dil, targetVolume.floatValue());
     474              }
    470475              dil.setDescription("Represents the remaining " + Values.formatNumber(extraVolume, 1) +
    471476                "µl aliquot after mixing " + Values.formatNumber(extraVolume*mixFactor, 1) +
     
    689694        lib.setAnnotation("mixFactor", (dilQuantity + usedQuantity) / usedQuantity);
    690695        // Add the used quantity back since we want the remaining quantity *before* pooling
     696        Float targetVolume = (Float)Annotationtype.POOL_TARGET_VOLUME_PER_LIB.getAnnotationValue(dc, dil);
     697        if (targetVolume != null)
     698        {
     699          lib.setAnnotation("targetVolume", targetVolume);
     700        }
    691701        if (remain != null) remain += dilQuantity;
    692702    }
Note: See TracChangeset for help on using the changeset viewer.