Changeset 1959


Ignore:
Timestamp:
May 3, 2013, 2:58:23 PM (9 years ago)
Author:
Nicklas Nordborg
Message:

References #479 and #485. Re-worked the process of selecing libraries for pooling. The first step will now create the PooledLibrary item and link to the used libraries with quantities. All calculations are base on pooling 5µl/2nM of each library. If a larger mix is required for a library dis is registed as a special item with .dil as a suffix. All items are registered without a creation date to indicate that it has yet to be done in the lab.

The lab protocol will use as much information as possible from the database.

Lots of error handling is still needed, and special cases are probably not well supported yet.

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

Legend:

Unmodified
Added
Removed
  • extensions/net.sf.basedb.reggie/trunk/resources/css/plate.css

    r1925 r1959  
    4242  border-bottom: 1px solid transparent;
    4343  border-right: 1px solid transparent;
    44   padding: 1px;
     44  padding: 2px;
    4545  overflow: hidden;
    4646  vertical-align: top;
     
    168168{
    169169  cursor: pointer;
    170   padding: 0px;
     170  padding: 1px;
    171171  border: 2px solid #2288AA;
    172172  border-radius: 4px;
     
    184184.well.highlight-row
    185185{
    186   padding-top: 0;
    187   padding-bottom: 0;
     186  padding-top: 1px;
     187  padding-bottom: 1px;
    188188  border-top: 2px solid #2288AA;
    189189  border-bottom: 2px solid #2288AA;
     
    193193.well.highlight-row:last-child
    194194{
    195   padding-right: 0;
     195  padding-right: 1px;
    196196  border-right: 2px solid #2288AA;
    197197  border-radius: 0 4px 4px 0;
     
    201201th.highlight-row
    202202{
    203   padding-left: 0;
     203  padding-left: 1px;
    204204  border-top: 2px solid #2288AA;
    205205  border-left: 2px solid #2288AA;
     
    211211.well.highlight-column
    212212{
    213   padding-left: 0;
    214   padding-right: 0;
     213  padding-left: 1px;
     214  padding-right: 1px;
    215215  border-left: 2px solid #2288AA;
    216216  border-right: 2px solid #2288AA;
     
    220220.plate tr:last-child .well.highlight-column
    221221{
    222   padding-bottom: 0;
     222  padding-bottom: 1px;
    223223  border-bottom: 2px solid #2288AA;
    224224  border-radius: 0 0 4px 4px;
     
    238238.well.pool-left.highlight-pool
    239239{
    240   padding-left: 0;
     240  padding-left: 1px;
    241241  border-left: 2px solid #2288AA;
    242242}
     
    245245.well.pool-right.highlight-pool
    246246{
    247   padding-right: 0;
     247  padding-right: 1px;
    248248  border-right: 2px solid #2288AA;
    249249}
     
    252252.row-0 .well.pool-left.highlight-pool
    253253{
    254   padding-top: 0;
     254  padding-top: 1px;
    255255  border-top: 2px solid #2288AA;
    256256  border-radius: 4px 0 0 0;
     
    258258.row-0 .well.pool-middle.highlight-pool
    259259{
    260   padding-top: 0;
     260  padding-top: 1px;
    261261  border-top: 2px solid #2288AA;
    262262}
    263263.row-0 .well.pool-right.highlight-pool
    264264{
    265   padding-top: 0;
     265  padding-top: 1px;
    266266  border-top: 2px solid #2288AA;
    267267  border-radius: 0 4px 0 0;
  • extensions/net.sf.basedb.reggie/trunk/resources/css/reggie.css

    r1897 r1959  
    5757}
    5858
    59 .stepform.disabled, .disabled .stepform
     59.stepform.disabled, .disabled .stepform, .stepform .disabled
    6060{
    6161  filter: url(filters.svg#grayscale); /* Firfox, etc */
  • extensions/net.sf.basedb.reggie/trunk/resources/index.jsp

    r1957 r1959  
    263263          <dd>
    264264            <ul>
    265             <li><a href="libprep/create_pools.jsp?ID=<%=ID%>" class="not-implemented">Create pooled libraries</a>
     265            <li><a href="libprep/create_pools.jsp?ID=<%=ID%>">Create pooled libraries</a>
    266266            <li><a href="libprep/pool_protocol.jsp?ID=<%=ID%>">Lab protocols for pooling</a> (preliminary)
    267267            <li><a href="libprep/pool_registration.jsp?ID=<%=ID%>" class="not-implemented">Register pooled libraries</a>
  • extensions/net.sf.basedb.reggie/trunk/resources/libprep/create_pools.jsp

    r1952 r1959  
    3232
    3333<script language="JavaScript">
    34 var debug = true;
     34var debug = false;
    3535var currentStep = 1;
    36 var LIMIT_FOR_5_ML = 1.0;
     36
     37// Loaded from servlet when getting Library information
     38var TARGET_MOLARITY_IN_POOL;
     39var TARGET_VOLUME_IN_POOL_PER_LIB;
    3740
    3841function init()
     
    7174  {
    7275    showLoadingAnimation('Loading Library bioplates...');
    73     var url = '../Pool.servlet?ID=<%=ID%>&cmd=GetLibraryPlatesForPooling';   
     76    var url = '../Pool.servlet?ID=<%=ID%>&cmd=GetLibraryPlatesForPooling';
    7477    request.open("GET", url, false); 
    7578    request.send(null);
     
    120123
    121124  var submitInfo = {};
    122  
    123125  submitInfo.pools = [];
    124126 
    125127  var numPools = Plate.getPools();
    126  
    127   for (var i = 0; i < numPools; i++)
    128   {
    129     var wells = Plate.getPool(i);
     128  for (var poolNo = 0; poolNo < numPools; poolNo++)
     129  {
     130    var wells = Plate.getPool(poolNo);
    130131   
    131132    var poolInfo = {};
    132     poolInfo.name = POOL_NAMES[i];
     133    poolInfo.name = POOL_NAMES[poolNo];
    133134    poolInfo.libs = [];
    134135   
    135     for (var j = 0; j < wells.length; j++)
    136     {
    137       var lib = wells[j].extract;
     136    for (var wellNo = 0; wellNo < wells.length; wellNo++)
     137    {
     138      var lib = wells[wellNo].extract;
    138139      if (lib)
    139140      {
     141        // We send library id, name and mixin volumes
    140142        var tmp = {};
    141143        tmp.id = lib.id;
    142144        tmp.name = lib.name;
    143145        tmp.volume = lib.volume;
     146        tmp.eb = lib.eb;
     147        tmp.extraMixFactor = lib.extraMixFactor;
    144148        poolInfo.libs[poolInfo.libs.length] = tmp;
    145149      }
     
    188192  Main.show('done');
    189193  Main.show('gorestart');
     194  scrollToBottom(document.getElementById('content'));
    190195
    191196}
     
    208213  try
    209214  {
    210     showLoadingAnimation('Loading Library bioplate information...');
     215    showLoadingAnimation('Loading information about libraries...');
    211216    var url = '../Pool.servlet?ID=<%=ID%>&cmd=GetLibraryInfoForPlate&bioplate='+libPlate.id;   
    212217    request.open("GET", url, false);
     
    226231  }
    227232 
     233  var poolInfo = response.poolInfo;
     234  TARGET_MOLARITY_IN_POOL = poolInfo.targetMolarity;
     235  TARGET_VOLUME_IN_POOL_PER_LIB = poolInfo.targetVolumePerLib;
     236 
     237  setInnerHTML('target_molarity', Numbers.formatNumber(TARGET_MOLARITY_IN_POOL, 1) + ' nM');
     238  setInnerHTML('target_volume', Numbers.formatNumber(TARGET_VOLUME_IN_POOL_PER_LIB, 1) + ' µl');
     239 
     240  // Pre-process the Library items
    228241  var list = response.libraries;
    229 
    230   // Pre-process the Library items
    231242  for (var i = 0; i < list.length; i++)
    232243  {
     
    292303  }
    293304 
    294   if (lib.molarity)
    295   {
    296     lib.volume = 10 / lib.molarity;
    297     lib.eb = 5-lib.volume;
     305  if (lib.volume)
     306  {
    298307    if (lib.speedVacConc != null)
    299308    {
    300309      remarks[remarks.length] = 'SpeedVac';
    301310    }
    302     if (lib.volume > 5)
    303     {
    304       remarks[remarks.length] = 'Use 5 µl';
    305       //lib.volume = 5;
    306       //lib.eb = 0;
    307     }
    308 
    309     if (lib.volume < LIMIT_FOR_5_ML)
    310     {
    311       lib.volume *= 2;
    312       lib.eb *= 2;
    313       remarks[remarks.length] = 'Mix 10µl';
     311    if (lib.volume > TARGET_VOLUME_IN_POOL_PER_LIB + 0.001)  // +0.001 to allow for rounding errors
     312    {
     313      remarks[remarks.length] = 'Use '+TARGET_VOLUME_IN_POOL_PER_LIB+' µl';
     314    }
     315
     316    if (lib.extraMixFactor)
     317    {
     318      // Larger mix than default
     319      var mixedVolume = (lib.volume+lib.eb)*(1+lib.extraMixFactor);
     320      remarks[remarks.length] = 'Mix ' + Numbers.formatNumber(mixedVolume, 0) + 'µl';
    314321    }
    315322
     
    333340  Plate.paint(Plate.getWells());
    334341  PoolSchema.buildPoolTableRow(schema, 12);
     342 
     343  for (var poolNo = 0; poolNo < Plate.getPools(); poolNo++)
     344  {
     345    var wells = Plate.getPool(poolNo);
     346    var poolMolarity = 0;
     347    var poolVolume = 0;
     348    var numLibs = 0;
     349    for (var wellNo = 0; wellNo < wells.length; wellNo++)
     350    {
     351      var lib = wells[wellNo].extract;
     352      if (lib)
     353      {
     354        poolMolarity += Math.min(lib.molarity, TARGET_MOLARITY_IN_POOL);
     355        poolVolume += TARGET_VOLUME_IN_POOL_PER_LIB;
     356        numLibs++;
     357      }
     358    }
     359   
     360    var poolData = '<div class="pool-data">';
     361    poolData += Numbers.formatNumber(poolMolarity/numLibs, 2)+'nM; ';
     362    poolData += Numbers.formatNumber(poolVolume, 0) + 'µl';
     363    poolData += '</div>';
     364    document.getElementById('pool.'+poolNo).innerHTML = POOL_NAMES[poolNo] + poolData;
     365  }
     366 
    335367}
    336368
     
    359391      var name = lib.name;
    360392      var i = name.indexOf('.m');
    361       text += '<div class="lib">'+name.substring(0, i)+'.<br>&nbsp;'+name.substring(i)+'</div>';
    362       text += '<div class="barcode">'+lib.barcode.name+'</div>';
    363       text += '<span class="volume">'+Numbers.formatNumber(lib.volume, 2) + 'µl</span>';
    364       text += '<span class="eb">'+Numbers.formatNumber(lib.eb, 2)+'µl</span>';
     393      var mixFactor = 1+lib.extraMixFactor;
     394      var displayName = name.substring(0, i)+'.<br>&nbsp;'+name.substring(i);
     395      text += '<div class="lib">'+displayName+'</div>';
     396      text += '<span class="barcode">'+lib.barcode.name+'</span>';
     397      text += '<span class="molarity">'+Numbers.formatNumber(lib.molarity, 2)+'nM</span>';
     398      text += '<span class="volume">'+Numbers.formatNumber(lib.volume*mixFactor, 2) + 'µl</span>';
     399      text += '<span class="eb">'+Numbers.formatNumber(lib.eb*mixFactor, 2)+'µl</span>';
    365400      text += '<div class="remarks">'+ lib.remarks.join('; ') + '</div>';
    366401    }
     
    377412  font-weight: bold;
    378413  margin-bottom: 0.25em;
     414  overflow: hidden;
     415  text-overflow: ellipsis;
     416}
     417.barcode
     418{}
     419.molarity
     420{
     421  float: right;
    379422}
    380423
     
    392435  color: #C80000;
    393436  font-style: italic;
     437}
     438.pool-data
     439{
     440  font-weight: normal;
    394441}
    395442</style>
     
    402449    /></p:path>
    403450
    404   <div class="content">
     451  <div class="content" id="content">
    405452  <%
    406453  if (sc.getActiveProjectId() == 0)
     
    420467  <tr>
    421468    <td rowspan="3" class="stepno">1</td>
    422     <td class="steptitle">Select Library bioplate</td>
     469    <td class="steptitle">Select source for pool</td>
    423470  </tr>
    424471  <tr>
     
    445492        <td class="prompt">Manual select</td>
    446493        <td class="input"> // TODO</td>
    447         <td class="status" id="bioplate.status"></td>
     494        <td class="status"></td>
    448495        <td class="help"></td>
    449496      </tr>
     
    473520        <td class="input">
    474521          <span id="barcode_variant"></span>
     522        </td>
     523        <td class="help"></td>
     524      </tr>
     525      <tr valign="top">
     526        <td class="prompt">Target molarity</td>
     527        <td class="input">
     528          <span id="target_molarity"></span>
     529        </td>
     530        <td class="help"></td>
     531      </tr>
     532      <tr valign="top">
     533        <td class="prompt">Target volume / lib</td>
     534        <td class="input">
     535          <span id="target_volume"></span>
    475536        </td>
    476537        <td class="help"></td>
     
    534595  <div id="done" class="success" style="display: none; width: 950px; margin-left: 20px; margin-top: 20px;"></div>
    535596 
    536   <table style="margin-left: 20px; margin-top: 10px;" class="navigation">
     597  <table style="margin-left: 20px; margin-top: 10px; margin-bottom: 3em;" class="navigation">
    537598    <tr>
    538599      <td><base:button id="gocancel" title="Cancel" onclick="goRestart(false)" /></td>
  • extensions/net.sf.basedb.reggie/trunk/resources/libprep/pool_protocol.jsp

    r1927 r1959  
    2828
    2929<script language="JavaScript">
    30 var debug = false;
     30var debug = true;
    3131var currentStep = 1;
    3232
     33var pools;
     34
    3335function init()
    3436{
    3537  var frm = document.forms['reggie'];
    36   var bioplates = getLibraryBioPlates();
    37  
    38   var plates = frm.bioplate;
    39   if (bioplates != null && bioplates.length > 0)
    40   {
    41     for (var i=0; i < bioplates.length; i++)
    42     {
    43       var bioplate = bioplates[i];
    44       var option = new Option(bioplate.name, bioplate.id);
    45       option.bioplate = bioplate;
    46       plates.options[plates.length] = option;
    47     }
    48     bioplateIsValid = true;
    49     bioPlateOnChange();
     38  pools = getUnpooledPools();
     39 
     40  var poolsList = frm.pools;
     41  var plateList = frm.bioplate;
     42 
     43  // We get a list of pools from the servlet
     44  // Each pool has a list of libraries
     45  // We want to find the Library bioplates that are unique
     46  // within a pool (eg. all libraries are from the same bioplate)
     47  if (pools != null && pools.length > 0)
     48  {
     49    var libPlates = [];
     50    for (var poolNo=0; poolNo < pools.length; poolNo++)
     51    {
     52      var pool = pools[poolNo];
     53     
     54      var libPlateForPool = null;
     55      for (var libNo = 0; libNo < pool.libraries.length; libNo++)
     56      {
     57        var lib = pool.libraries[libNo];
     58        var libPlate = lib.bioWell.bioPlate;
     59       
     60        if (libNo == 0)
     61        {
     62          libPlateForPool = libPlate;
     63        }
     64        else if (libPlateForPool.id != libPlate.id)
     65        {
     66          libPlateForPool = null;
     67          break;
     68        }
     69      }
     70     
     71      // Store the library bioplate
     72      pool.libPlate = libPlateForPool;
     73     
     74      // If the pool has a single library bioplate add it to the selection list
     75      // If the pool doesn't have a single library bioplate, nothing is added to
     76      // the list and the pool can only be selected when the 'multiple' option is
     77      // active for the bioplates list
     78      if (libPlateForPool != null && !libPlates[libPlateForPool.name])
     79      {
     80        libPlates[libPlateForPool.name] = libPlateForPool;
     81        var plateOption = new Option(libPlateForPool.name, libPlateForPool.id);
     82        plateOption.plate = libPlateForPool;
     83        plateList[plateList.length] = plateOption;
     84      }
     85
     86    }
     87    if (plateList.length > 1) plateList.selectedIndex = 1;
     88    bioplateOnChange();
    5089    Main.show('gocreate');
    5190  }
    5291  else
    5392  {
    54     var msg = 'No Library bioplates available for processing.';
     93    var msg = 'No pools available for processing.';
    5594    setFatalError(msg);
    5695    return;
     
    6099
    61100
    62 function getLibraryBioPlates()
     101function getUnpooledPools()
    63102{
    64103  var frm = document.forms['reggie'];
     
    67106  try
    68107  {
    69     showLoadingAnimation('Loading Library bioplates...');
    70     var url = '../Pool.servlet?ID=<%=ID%>&cmd=GetLibraryPlatesForPooling';   
     108    showLoadingAnimation('Loading unprocessed pools...');
     109    var url = '../Pool.servlet?ID=<%=ID%>&cmd=GetUnprocessedPools';   
    71110    request.open("GET", url, false); 
    72111    request.send(null);
     
    84123    return false;
    85124  }
    86   return response.bioplates;
     125  return response.pools;
     126}
     127
     128// Add pools to the pools list based on the bioplate selection
     129function bioplateOnChange()
     130{
     131  var frm = document.forms['reggie'];
     132 
     133  var libPlateId = parseInt(frm.bioplate.value);
     134
     135  // Clear current list
     136  frm.pools.length = 0;
     137 
     138  for (var poolNo = 0; poolNo < pools.length; poolNo++)
     139  {
     140    var pool = pools[poolNo];
     141    // If a libplate is selected, only show pools that have all libraries from that plate
     142    // If no libplate is selected, only show pools that have libraries from multiple plates
     143    var addPool = (libPlateId && pool.libPlate.id == libPlateId) || (!libPlateId && pool.libPlate == null);
     144    if (addPool)
     145    {
     146      frm.pools[frm.pools.length] = new Option(pool.name, pool.id, libPlateId);
     147    }
     148  }
     149 
     150  setInputStatus('pools', '', '');
     151  if (libPlateId)
     152  {
     153    frm.pools.disabled = true;
     154    Main.removeClass(document.getElementById('plateview'), 'disabled');
     155  }
     156  else
     157  {
     158    frm.pools.disabled = false;
     159    Main.addClass(document.getElementById('plateview'), 'disabled');
     160  }
    87161}
    88162
     
    91165{
    92166  var frm = document.forms['reggie'];
    93   if (frm.bioplate && !frm.bioplate.disabled)
    94   {
    95     frm.view.value = type;
    96     frm.submit();
    97   }
    98 }
    99 
    100 function bioPlateOnChange()
    101 {
    102   var frm = document.forms['reggie'];
    103   var bioplate = frm.bioplate[frm.bioplate.selectedIndex].bioplate;
    104   setInnerHTML('comments', formatText(bioplate.comments));
    105   frm.poolSchema.value = bioplate.poolSchema;
    106   frm.barcodeVariant.value = bioplate.barcodeVariant;
     167  var libPlateId = parseInt(frm.bioplate.value);
     168 
     169  if (libPlateId == 0)
     170  {
     171    // 'multiple' option selected, check that at least one pool is selected
     172    var numSelectedPools = 0;
     173    for (var poolNo = 0; poolNo < frm.pools.length; poolNo++)
     174    {
     175      if (frm.pools[poolNo].selected) numSelectedPools++;
     176    }
     177   
     178    if (numSelectedPools == 0)
     179    {
     180      setInputStatus('pools', 'Select at least one pool', 'invalid');
     181      return;
     182    }
     183    setInputStatus('pools', '', 'valid');
     184  }
     185
     186  frm.pools.disabled = false;
     187  frm.view.value = type;
     188  frm.submit();
     189  frm.pools.disabled = (libPlateId != 0);
    107190}
    108191
    109192</script>
    110 <style>
    111 #export div
    112 {
    113   margin-left: 1em;
    114 }
    115 </style>
    116193</base:head>
    117194<base:body onload="init()">
     
    138215  <input type="hidden" name="ID" value="<%=ID%>">
    139216  <input type="hidden" name="view" value="list">
    140   <input type="hidden" name="poolSchema" value="4by24">
    141   <input type="hidden" name="barcodeVariant" value="">
    142217 
    143218  <table class="stepform">
    144219  <tr>
    145220    <td rowspan="3" class="stepno">1</td>
    146     <td class="steptitle">Select Library bioplate</td>
     221    <td class="steptitle">Select pools</td>
    147222  </tr>
    148223  <tr>
     
    150225      <table>
    151226      <tr valign="top">
    152         <td class="prompt">Library bioplate</td>
    153         <td class="input"><select style="width:90%"
    154             name="bioplate" id="bioplate" onchange="bioPlateOnChange()"></select>
     227        <td class="prompt">Library plate</td>
     228        <td class="input">
     229          <select style="width:90%;" name="bioplate" id="bioplate" onchange="bioplateOnChange()">
     230            <option value="0">- multiple -
     231          </select>
     232          <br>
     233          <i>- or -</i>
    155234        </td>
    156235        <td class="status" id="bioplate.status"></td>
    157         <td class="help" rowspan="2"><span id="bioplate.message" class="message" style="display: none;"></span>
    158           Select an existing Library bioplate. The list contain all Library bioplates that
    159           has not yet been pooled (determined by ????).
     236        <td class="help"><span id="bioplate.message" class="message" style="display: none;"></span>
     237          Select the library bioplate that should be pooled in this step. The list contains
     238          all plates with pools that has not yet been created (determined by abscense of creation date).
     239          Use the <b>multiple</b> option to select pools with libraries from multiple plates.
    160240        </td>
    161241      </tr>
    162242      <tr valign="top">
    163         <td class="subprompt">-comments</td>
    164         <td class="input" id="comments" style="font-style: italic; background: #E8E8E8; padding: 2px 5px 2px 5px;"></td>
    165         <td class="status" id="comments.status"></td>
     243        <td class="prompt">Pools</td>
     244        <td class="input"><select style="width:90%;" size="6"
     245            name="pools" id="pools" multiple></select>
     246        </td>
     247        <td class="status" id="pools.status"></td>
     248        <td class="help"><span id="pools.message" class="message" style="display: none;"></span>
     249          Select the pools to work with.
     250        </td>
    166251      </tr>
    167252      <tr valign="top">
    168253        <td class="prompt">Lab protocols</td>
    169254        <td class="input" id="protocol" style="white-space: nowrap; line-height: 1.5em;">
    170           <span class="link" onclick="viewProtocol('list')"><img src="../images/listview.png">&nbsp;List layout</span><br>
    171           <span class="link" onclick="viewProtocol('plate')"><img src="../images/plateview.png">&nbsp;Plate layout</span><br>
     255          <span id="listview" class="link" onclick="viewProtocol('list')"><img src="../images/listview.png">&nbsp;List layout</span><br>
     256          <span id="plateview" class="link" onclick="viewProtocol('plate')"><img src="../images/plateview.png">&nbsp;Plate layout</span><br>
    172257        </td>
    173258        <td class="status" id="protocol.status"></td>
     
    177262        </td>
    178263      </tr>
     264      </table>
     265    </td>
    179266  </tr>
    180267  </table>
  • extensions/net.sf.basedb.reggie/trunk/resources/libprep/pool_protocol2.jsp

    r1950 r1959  
    1616  import="net.sf.basedb.core.query.Restrictions"
    1717  import="net.sf.basedb.core.query.Hql"
     18  import="net.sf.basedb.core.query.Orders"
    1819  import="net.sf.basedb.util.Values"
    1920  import="net.sf.basedb.util.formatter.WellCoordinateFormatter"
     
    3637  final Extension reggie = ExtensionsControl.get(dc).getExtension("net.sf.basedb.reggie");
    3738  final User user = User.getById(dc, sc.getLoggedInUserId());
     39 
     40  Integer[] pools = Values.getInt(request.getParameterValues("pools"));
     41 
    3842  int libPlateId = Values.getInt(request.getParameter("bioplate"));
    39   String poolSchema = request.getParameter("poolSchema");
    40   String barcodeVariant = request.getParameter("barcodeVariant");
    41  
    42   BioPlate plate = BioPlate.getById(dc, libPlateId);
    43   int columns = plate.getColumns();
    44   int rows = plate.getRows();
     43  BioPlate libPlate = libPlateId == 0 ? null : BioPlate.getById(dc, libPlateId);
    4544  String view = Values.getString(request.getParameter("view"), "list");
    4645%>
     
    5251  <link rel="stylesheet" type="text/css" href="<%=home %>/css/printable.css">
    5352  <link rel="stylesheet" type="text/css" href="<%=home %>/css/plate.css">
     53  <link rel="stylesheet" type="text/css" href="<%=home %>/css/reggie.css">
    5454  <script language="JavaScript" src="<%=root%>/include/scripts/main.js" type="text/javascript" charset="UTF-8"></script>
    5555  <script language="JavaScript" src="<%=root%>/include/scripts/ajax.js" type="text/javascript" charset="UTF-8"></script>
     
    5959 
    6060  <script language="JavaScript">
    61   var debug = false;
     61  var debug = true;
    6262  var currentStep = 1;
    63   var LIMIT_FOR_5_ML = 1.0;
     63 
     64  // Loaded from servlet when getting Library information
     65  var TARGET_MOLARITY_IN_POOL;
     66  var TARGET_VOLUME_IN_POOL_PER_LIB; 
     67  var POOL_SCHEMA;
     68  var POOL_BARCODE_VARIANT;
    6469 
    6570  function init()
    6671  {
    67     var schema = PoolSchema.getById('<%=poolSchema%>');
    68     var barcodeVariant = PoolSchema.getBarcodeVariantByName(schema, '<%=barcodeVariant%>');
    69 
    70     // Load Libraries and related info from the selected bioplate
     72    // Load information about Library bioplate
     73    <%
     74    if (libPlateId != 0)
     75    {
     76      %>
     77      // Load Libraries and related info from the selected pools
     78      var request = Ajax.getXmlHttpRequest();
     79      try
     80      {
     81        showLoadingAnimation('Loading library bioplate information...');
     82        var url = '../Pool.servlet?ID=<%=ID%>&cmd=GetLibPlateInfo&bioplate=<%=libPlateId%>';   
     83        request.open("GET", url, false);
     84        request.send(null);
     85      }
     86      finally
     87      {
     88        hideLoadingAnimation();
     89      }
     90     
     91      if (debug) Main.debug(request.responseText);
     92      var response = JSON.parse(request.responseText);
     93      if (response.status != 'ok')
     94      {
     95        setFatalError(response.message);
     96        return false;
     97      }
     98     
     99      var libPlate = response.libPlate;
     100     
     101      POOL_SCHEMA = PoolSchema.getById(libPlate.poolSchema);
     102      POOL_BARCODE_VARIANT = PoolSchema.getBarcodeVariantByName(POOL_SCHEMA, libPlate.barcodeVariant);
     103      <%
     104    }
     105    %>
     106   
     107    var pools = [<%=Values.getString(java.util.Arrays.asList(pools), ",", true)%>];
     108
     109    // Load Libraries and related info from the selected pools
    71110    var request = Ajax.getXmlHttpRequest();
    72111    try
    73112    {
    74       showLoadingAnimation('Loading Library bioplate information...');
    75       var url = '../Pool.servlet?ID=<%=ID%>&cmd=GetLibraryInfoForPlate&bioplate=<%=libPlateId%>';   
     113      showLoadingAnimation('Loading pooled library information...');
     114      var url = '../Pool.servlet?ID=<%=ID%>&cmd=GetLibraryInfoForPools&pools='+pools.join(',');   
    76115      request.open("GET", url, false);
    77116      request.send(null);
     
    90129    }
    91130   
    92     var list = response.libraries;
    93 
     131    var pools = response.pools;
     132    var poolInfo = response.poolInfo;
     133    TARGET_MOLARITY_IN_POOL = poolInfo.targetMolarity;
     134    TARGET_VOLUME_IN_POOL_PER_LIB = poolInfo.targetVolumePerLib;
     135
     136    var list = [];
    94137    // Pre-process the Library items
    95     for (var i = 0; i < list.length; i++)
    96     {
    97       checkAndPreProcessLibrary(list[i], schema, barcodeVariant);
     138    for (var i = 0; i < pools.length; i++)
     139    {
     140      var pool = pools[i];
     141      for (var j = 0; j < pool.libraries.length; j++)
     142      {
     143        checkAndPreProcessLibrary(pool.libraries[j], POOL_SCHEMA, POOL_BARCODE_VARIANT);       
     144      }
    98145    }
    99146   
     
    102149    {
    103150      %>
    104       viewAsList(list, schema, barcodeVariant);
     151      viewAsList(pools, POOL_SCHEMA, POOL_BARCODE_VARIANT);
    105152      <%
    106153    }
     
    108155    {
    109156      %>
    110       viewAsPlate(list, schema, barcodeVariant)
     157      viewAsPlate(pools, POOL_SCHEMA, POOL_BARCODE_VARIANT)
    111158      <%
    112159    }
     
    120167
    121168    // Check if default barcode has been modified
    122     var indexSet = barcodeVariant.indexSets[well.column];
    123     if (indexSet)
    124     {
    125       var defaultBarcode = indexSet.barcodes[well.row];
    126       if (defaultBarcode && lib.barcode.name != defaultBarcode)
    127       {
    128         remarks[remarks.length] = 'Modified barcode';
    129         lib.barcode.modified = true;
    130       }
    131     }
    132    
    133     // Calculate volume to use and water to add based on concentration
     169    if (barcodeVariant)
     170    {
     171      var indexSet = barcodeVariant.indexSets[well.column];
     172      if (indexSet)
     173      {
     174        var defaultBarcode = indexSet.barcodes[well.row];
     175        if (defaultBarcode && lib.barcode.name != defaultBarcode)
     176        {
     177          remarks[remarks.length] = 'Modified barcode';
     178          lib.barcode.modified = true;
     179        }
     180      }
     181    }
     182   
    134183    if (lib.molarity)
    135184    {
    136       lib.volume = 10 / lib.molarity;
    137       lib.eb = 5-lib.volume;
    138185      if (lib.speedVacConc != null)
    139186      {
    140187        remarks[remarks.length] = 'SpeedVac';
    141         if (lib.molarity < 2) remarks[remarks.length] = 'Use 5 µl';
    142       }
    143       if (lib.volume < LIMIT_FOR_5_ML)
    144       {
    145         lib.volume *= 2;
    146         lib.eb *= 2;
    147         remarks[remarks.length] = 'Mix 10µl';
    148       }
    149     }
    150 
    151     lib.remarks = remarks;
     188      }
     189      if (lib.volume > TARGET_VOLUME_IN_POOL_PER_LIB + 0.001)
     190      {
     191        remarks[remarks.length] = 'Use 5 µl';
     192      }
     193 
     194      if (lib.extraMixFactor)
     195      {
     196        // Larger mix than default
     197        var mixedVolume = (lib.volume+lib.eb)*(1+lib.extraMixFactor);
     198        remarks[remarks.length] = 'Mix ' + Numbers.formatNumber(mixedVolume, 0) + 'µl';
     199      }
     200
     201      lib.remarks = remarks;
     202    }
    152203  }
    153204 
     
    168219 
    169220 
    170   function viewAsList(list, schema, barcodeVariant)
     221  function viewAsList(pools, schema, barcodeVariant)
    171222  {
    172223    var lastPoolNum = -1;
    173     for (var i = 0; i < list.length; i++)
    174     {
    175       var lib = list[i];
    176       var well = lib.bioWell;
    177  
    178       var idSuffix = well.column + '.' + well.row;
    179       if (lib.remainingQuantity)
    180       {
     224    for (var i = 0; i < pools.length; i++)
     225    {
     226      var pool = pools[i];
     227     
     228      var html = '';
     229      var tbody = document.getElementById('listview.'+pool.id+'.body');
     230     
     231      for (var j = 0; j < pool.libraries.length; j++)
     232      {
     233        var lib = pool.libraries[j];
     234        var well = lib.bioWell;
     235       
     236        var tr = document.createElement('tr');
     237        tr.className = well.column % 2 == 0 ? "evencol" : "oddcol";
     238   
     239        if (barcodeVariant)
     240        {
     241          var indexSet = barcodeVariant.indexSets[well.column];
     242          if (indexSet)
     243          {
     244            tr.className = lib && lib.barcode.modified ? 'bg-modified' : indexSet.color;
     245          }
     246        }
     247
     248        addColumn(tr, "lib", lib.name);
     249        addColumn(tr, "remain", Numbers.formatNumber((lib.remainingQuantity+lib.usedQuantity)*1000, 2));
     250        addColumn(tr, "molarity", Numbers.formatNumber(lib.molarity, 2));
     251        <%
     252        if (libPlate==null)
     253        {
     254          %>
     255          addColumn(tr, "workplate", well.bioPlate.name + ' ' + well.location);
     256          <%
     257        }
     258        else
     259        {
     260          %>
     261          addColumn(tr, "workplate", well.location);
     262          <%
     263        }
     264        %>
     265        addColumn(tr, "mix", '<span class="volume">'+Numbers.formatNumber(lib.volume, 2)+'</span>+<span class="eb">'+Numbers.formatNumber(lib.eb, 2)+'</span>');
     266        addColumn(tr, "remarks", lib.remarks.join('; '));
     267        tbody.appendChild(tr);
     268        /*
     269        var idSuffix = well.column + '.' + well.row;
    181270        Main.removeClass(document.getElementById('row.'+idSuffix), 'empty');
    182271        setInnerHTML('lib.'+idSuffix, lib.name);
    183         setInnerHTML('pool.'+idSuffix, '????');
    184         setInnerHTML('remain.'+idSuffix, Numbers.formatNumber(lib.remainingQuantity*1000, 2));
     272        setInnerHTML('pool.'+idSuffix, pool.name);
     273        setInnerHTML('remain.'+idSuffix, Numbers.formatNumber((lib.remainingQuantity+lib.usedQuantity)*1000, 2));
    185274        setInnerHTML('molarity.'+idSuffix, Numbers.formatNumber(lib.molarity, 2));
    186275       
     
    196285       
    197286        setInnerHTML('remarks.'+idSuffix, lib.remarks.join('; '));
    198       }
    199     }
    200   }
    201  
    202  
    203   function viewAsPlate(list, schema, barcodeVariant)
    204   {
    205     Plate.init(<%=rows%>, <%=columns%>, schema, WellPainter);
    206    
    207     for (var i = 0; i < list.length; i++)
    208     {
    209       var lib = list[i];
    210       var well = lib.bioWell;
    211       Plate.getWell(well.row, well.column).setExtract(lib);
     287        */
     288       
     289      }
     290     
     291      setInnerHTML('molarity.'+pool.id, Numbers.formatNumber(pool.molarity, 2) + ' nM; ' + Numbers.formatNumber(1000*pool.originalQuantity / pool.conc, 0)+' µl');
     292      Main.show('pool.'+pool.id);
     293    }
     294  }
     295 
     296  function addColumn(tr, className, html)
     297  {
     298   
     299    var td = document.createElement('td');
     300    td.className = className;
     301    td.innerHTML = html;
     302    tr.appendChild(td);
     303   
     304  }
     305 
     306  function viewAsPlate(pools, schema, barcodeVariant)
     307  {
     308    Plate.init(8, 12, schema, WellPainter);
     309   
     310    for (var i = 0; i < pools.length; i++)
     311    {
     312      var pool = pools[i];
     313      POOL_NAMES[i] = pool.name;
     314      for (var j = 0; j < pool.libraries.length; j++)
     315      {
     316        var lib = pool.libraries[j];
     317        var well = lib.bioWell;
     318        Plate.getWell(well.row, well.column).setExtract(lib);
     319      }
    212320    }
    213321
    214322    WellPainter.barcodeVariant = barcodeVariant;
    215323    Plate.paint(Plate.getWells());
    216     PoolSchema.buildPoolTableRow(schema, <%=columns%>);
     324    PoolSchema.buildPoolTableRow(schema, 12);
    217325    Main.show('plateview');
    218326  }
     
    238346      var text = '';
    239347      var lib = well.extract;
    240       if (lib && lib.remainingQuantity)
     348      if (lib)
    241349      {
    242350        var name = lib.name;
     351        var mixFactor = 1+(lib.extraMixFactor || 0);
    243352        var i = name.indexOf('.m');
    244353        text += '<div class="lib">'+name.substring(0, i)+'.<br>&nbsp;'+name.substring(i)+'</div>';
    245         text += '<div><span class="volume">'+Numbers.formatNumber(lib.volume, 1)+'µl</span>';
    246         text += '<span class="eb">'+Numbers.formatNumber(lib.eb, 1)+'µl</span></div>';
     354        text += '<div><span class="volume">'+Numbers.formatNumber(lib.volume*mixFactor, 1)+'µl</span>';
     355        text += '<span class="eb">'+Numbers.formatNumber(lib.eb*mixFactor, 1)+'µl</span></div>';
    247356        text += '<div class="remarks">'+ lib.remarks.join('; ') + '</div>';
    248357      }
     
    266375  table.protocolheader > tbody > tr > th
    267376  {
    268     width: 50%;
    269377    text-align: left;
    270378    font-size: 1em;
    271379  }
    272  
    273   #listview
     380
     381  table.poolheader
     382  {
     383    margin-top: 1em;
     384    width: 100%;
     385  }
     386
     387  table.poolheader > tbody > tr
     388  {
     389    height: 1.25em;
     390  }
     391
     392  table.poolheader > tbody > tr > th
     393  {
     394    text-align: left;
     395    font-size: 1em;
     396  }
     397 
     398  .listview
    274399  {
    275400    width: 100%;
     
    279404  }
    280405 
    281   #listview tr.evencol
     406  .listview tr.oddcol
    282407  {
    283408    background-color: #F0F0F0;
    284409  }
    285410 
    286   #listview thead
     411  .listview thead
    287412  {
    288413    border: 1px solid #000000;
     
    290415  }
    291416 
    292   #listview tbody
     417  .listview tbody
    293418  {
    294419    page-break-inside: avoid;
     
    297422  }
    298423 
    299   #listview th
     424  .listview th
    300425  {
    301426    border-left: 1px solid #000000;
    302427  }
    303428 
    304   #listview td
     429  .listview td
    305430  {
    306431    border-left: 1px solid #000000;
     
    309434  }
    310435 
    311   #listview .col-num
     436  .listview .col-num
    312437  {
    313438    width: 1.75em;
     
    318443  }
    319444 
    320   #listview .lib
     445  .listview .lib
    321446  {
    322447    width: 15em;
     
    324449  }
    325450 
    326   #listview .empty .lib
     451  .listview .empty .lib
    327452  {
    328453    font-style: italic;
     
    331456  }
    332457 
    333   #listview .workplate
     458  .listview .workplate
     459  {
     460 
     461    width: <%=libPlate==null ? "14em" : "7em"%>;
     462    text-align: center;
     463  }
     464 
     465  .listview .pool
    334466  {
    335467    width: 7em;
     
    337469  }
    338470 
    339   #listview .pool
    340   {
    341     width: 7em;
    342     text-align: center;
    343   }
    344  
    345   #listview .remain, #listview .molarity
     471  .listview .remain, .listview .molarity
    346472  {
    347473    width: 4.5em;
     
    350476  }
    351477
    352   #listview .mix
     478  .listview .mix
    353479  {
    354480    width: 8em;
     
    357483  }
    358484 
    359   #listview .empty .mix
     485  .listview .empty .mix
    360486  {
    361487    visibility: hidden;
    362488  }
    363489 
    364   #listview .volume
     490  .listview .volume
    365491  {
    366492    color: #C80000;
     
    368494  }
    369495 
    370   #listview .eb
     496  .listview .eb
    371497  {
    372498    color: #0000C8;
     
    374500  }
    375501 
    376   #listview .remarks
     502  .listview .remarks
    377503  {
    378504    vertical-align: top;
     
    450576
    451577  <table style="width: 100%; border: 0px;" class="protocolheader">
    452   <tr valign="top">
    453     <th style="width: 40%;">Work plate: <%=HTML.encodeTags(plate.getName())%></th>
    454     <th style="width: 60%">Comments:</th>
    455   </tr>
     578  <%
     579  if (libPlate != null)
     580  {
     581    %>
     582    <tr valign="top">
     583      <th style="width: 40%;">Library plate: <%=HTML.encodeTags(libPlate.getName()) %></th>
     584      <td></td>
     585    </tr>
     586    <%
     587  }
     588  %>
    456589  <tr valign="top">
    457590    <th style="width: 40%; padding-bottom: 1.5em;">Date+operator:</th>
    458     <td><%=HTML.niceFormat(plate.getDescription()) %></td>
     591    <td></td>
    459592  </tr>
    460593  </table>
     594
     595  <%
     596  if (view.equals("list"))
     597  {
     598    for (Integer poolId :pools)
     599    {
     600      Extract pool = Extract.getById(dc, poolId);
     601      %>
     602      <div id="pool.<%=poolId%>" style="display: none;">
     603      <table style="width: 100%; border: 0px;" class="poolheader">
     604      <tr valign="top">
     605        <th style="width: 40%;"><%=HTML.encodeTags(pool.getName())%></th>
     606        <th style="width: 60%">Comments:</th>
     607      </tr>
     608      <tr valign="top">
     609        <td style="width: 40%;"><span id="molarity.<%=poolId%>" </td>
     610        <td><%=HTML.niceFormat(pool.getDescription()) %></td>
     611      </tr>
     612      </table>
     613      <table style="width: 100%;" class="listview" id="listview.<%=poolId%>">
     614      <thead>
     615        <tr class="toprow">
     616          <th class="lib"></th>
     617          <th>Remain</th>
     618          <th>DNA</th>
     619          <th class="workplate">Work</th>
     620          <th>2nM, 5/10µl</th>
     621          <th></th>
     622        </tr>
     623        <tr>
     624          <th class="lib">Library</th>
     625          <th>(ng)</th>
     626          <th>(nM)</th>
     627          <th class="workplate">plate</th>
     628          <th>(µl)</th>
     629          <th>Remarks</th>
     630        </tr>
     631      </thead>
     632      <tbody id="listview.<%=poolId%>.body">
     633      </tbody>
     634      </table>
     635      </div>
     636      <%
     637    }
     638  }
     639  %>
    461640
    462641  <div class="loading" id="loading" style="display: none;"><table><tr><td><img src="../images/loading.gif"></td><td id="loading.msg">Please wait...</td></tr></table></div>
    463642  <div class="messagecontainer error" id="errorMessage" style="display: none;"></div>
    464643  <%
    465   if (view.equals("list"))
    466   {
    467     %>
    468     <table style="width: 100%;" id="listview">
    469     <thead>
    470       <tr class="toprow">
    471         <th></th>
    472         <th></th>
    473         <th class="lib"></th>
    474         <th>Remain</th>
    475         <th>DNA</th>
    476         <th class="workplate">Work</th>
    477         <th>2nM, 5/10µl</th>
    478         <th></th>
    479       </tr>
    480       <tr>
    481         <th></th>
    482         <th>Pool</th>
    483         <th class="lib">Library</th>
    484         <th>(ng)</th>
    485         <th>(nM)</th>
    486         <th class="workplate">plate</th>
    487         <th>(µl)</th>
    488         <th>Remarks</th>
    489       </tr>
    490     </thead>
    491     <%
    492     WellCoordinateFormatter rowF = new WellCoordinateFormatter(true);
    493     WellCoordinateFormatter colF = new WellCoordinateFormatter(false);
    494     for (int c = 0; c < columns; ++c)
    495     {
    496       String rowClass = c % 2 == 0 ? "evencol" : "oddcol";
    497       %>
    498       <tbody>
    499       <%
    500       for (int r = 0; r < rows; ++r)
    501       {
    502         String idSuffix = c + "." + r;
    503         %>
    504         <tr class="<%=rowClass%> empty" id="row.<%=idSuffix%>">
    505           <%
    506           if (r == 0)
    507           {
    508             %>
    509             <td class="col-num" rowspan="<%=rows%>"><%=c+1%></td>
    510             <%
    511           }
    512           %>
    513           <td class="pool" id="pool.<%=idSuffix%>"></td>
    514           <td class="lib" id="lib.<%=idSuffix%>">empty</td>
    515           <td class="remain" id="remain.<%=idSuffix%>"></td>
    516           <td class="molarity" id="molarity.<%=idSuffix%>"></td>
    517           <td class="workplate"><%=rowF.format(r)+colF.format(c)%></td>
    518           <td class="mix"><span class="volume" id="volume.<%=idSuffix%>"></span>+<span class="eb" id="eb.<%=idSuffix%>"></span></td>
    519           <td class="remarks" id="remarks.<%=idSuffix%>"></td>
    520         </tr>
    521         <%
    522       }
    523       %>
    524       </tbody>
    525       <%
    526     }
    527     %>
    528     </table>
    529     <%
    530   }
    531   else
     644
     645  if (view.equals("plate"))
    532646  {
    533647    %>
     
    540654      <th></th>
    541655      <%
    542       for (int c = 0; c < columns; ++c)
     656      for (int c = 0; c < libPlate.getColumns(); ++c)
    543657      {
    544658        %>
     
    550664    <tbody>
    551665    <%
    552     for (int r = 0; r < rows; ++r)
     666    for (int r = 0; r < libPlate.getRows(); ++r)
    553667    {
    554668      String row = rowF.format(r);
     
    557671        <th id="row.<%=r%>" class="rowheader"><%=row%></th>
    558672        <%
    559         for (int c = 0; c < columns; ++c)
     673        for (int c = 0; c < libPlate.getColumns(); ++c)
    560674        {
    561675          %>
  • extensions/net.sf.basedb.reggie/trunk/resources/reggie.js

    r1938 r1959  
    387387  text = text.replace(/\n/g, '<br>');
    388388  return text;
     389}
     390
     391function scrollToBottom(element)
     392{
     393  element.scrollTop = element.scrollHeight;
    389394}
    390395
  • extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/dao/Annotationtype.java

    r1925 r1959  
    408408    new Annotationtype("CA_Molarity", Type.FLOAT, Item.EXTRACT);
    409409
     410  /**
     411    The "PoolConc" annotation, used for extracts (PooledLibrary).
     412    Automatically calculated from the quantities used from the
     413    libraries mixed in the pool.
     414    @since 2.12
     415  */
     416  public static final Annotationtype POOL_CONC =
     417    new Annotationtype("PoolConc", Type.FLOAT, Item.EXTRACT);
     418
     419  /**
     420    The "PoolMolarity" annotation, used for extracts (PooledLibrary).
     421    Automatically calculated using the molarity from from the
     422    libraries mixed in the pool.
     423    @since 2.12
     424  */
     425  public static final Annotationtype POOL_MOLARITY =
     426    new Annotationtype("PoolMolarity", Type.FLOAT, Item.EXTRACT);
    410427 
    411428  /**
  • extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/dao/Library.java

    r1894 r1959  
    77import org.json.simple.JSONObject;
    88
    9 import net.sf.basedb.core.BioPlate;
    109import net.sf.basedb.core.BioWell;
    1110import net.sf.basedb.core.DbControl;
    1211import net.sf.basedb.core.Extract;
     12import net.sf.basedb.core.ItemQuery;
    1313import net.sf.basedb.core.Tag;
     14import net.sf.basedb.core.query.Hql;
     15import net.sf.basedb.core.query.Orders;
     16import net.sf.basedb.reggie.JsonUtil;
     17import net.sf.basedb.reggie.Reggie;
    1418
    1519/**
     
    3135  }
    3236 
     37 
     38  @SuppressWarnings("unchecked")
     39  public static List<Library> getByPool(DbControl dc, PooledLibrary pool)
     40  {
     41    ItemQuery<Extract> libQuery = (ItemQuery<Extract>)pool.getExtract().getCreationEvent().getSources();
     42    Subtype.LIBRARY.addFilter(dc, libQuery);
     43    libQuery.include(Reggie.INCLUDE_IN_CURRENT_PROJECT);
     44   
     45    libQuery.join(Hql.innerJoin(null, "bioWell", "bw", true));
     46    libQuery.join(Hql.innerJoin("bw", "bioPlate", "bp", true));
     47   
     48    libQuery.order(Orders.asc(Hql.property("bp", "name")));
     49    libQuery.order(Orders.asc(Hql.property("bw", "column")));
     50    libQuery.order(Orders.asc(Hql.property("bw", "row")));
     51   
     52    List<Extract> tmp = libQuery.list(dc);
     53
     54    return toList(tmp);
     55  }
    3356 
    3457  public static List<Library> toList(Collection<Extract> extracts)
     
    82105    is located on.
    83106  */
    84   @SuppressWarnings("unchecked")
    85107  public JSONObject loadBioPlateLocation()
    86108  {
    87109    if (jsonWell != null) return jsonWell;
    88110
    89     Extract cdna = getItem();
    90     BioWell well = cdna.getBioWell();
     111    Extract lib = getItem();
     112    BioWell well = lib.getBioWell();
    91113
    92114    if (well != null)
    93115    {
    94       jsonWell = new JSONObject();
    95       jsonWell.put("id", well.getId());
    96       jsonWell.put("row", well.getRow());
    97       jsonWell.put("column", well.getColumn());
    98      
    99       BioPlate plate = well.getPlate();
    100       JSONObject jsonPlate = new JSONObject();
    101       jsonPlate.put("id", plate.getId());
    102       jsonPlate.put("name", plate.getName());
    103    
    104       jsonWell.put("bioPlate", jsonPlate);
     116      jsonWell = JsonUtil.getBioWellAsJSON(well);
    105117    }
    106118
  • extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/dao/PooledLibrary.java

    r1934 r1959  
    8181  }
    8282
    83  
     83  /**
     84    Find pooled libraries that have not yet been processed. The query will look for
     85    extract with the {@link Subtype#POOLED_LIBRARY} subtype that has no 'created' date.
     86    The list is sorted by name.
     87  */
     88  public static List<PooledLibrary> findUnprocessedPools(DbControl dc)
     89  {
     90    List<PooledLibrary> pools = new ArrayList<PooledLibrary>();
     91   
     92    // Create a query that load all Lysate extracts without created date
     93    ItemQuery<Extract> query = Extract.getQuery();
     94    query.setIncludes(Reggie.INCLUDE_IN_CURRENT_PROJECT);
     95    // Filter on Lysate subtype
     96    Subtype.POOLED_LIBRARY.addFilter(dc, query);
     97    // Filter on created date
     98    query.restrict(Restrictions.eq(Hql.property("ce", "eventDate"), null));
     99   
     100    // Join the creation event and bioplate
     101    query.join(Hql.innerJoin("creationEvent", "ce"));
     102   
     103    // Sort by name
     104    query.order(Orders.asc(Hql.property("name")));
     105       
     106    return toList(query.list(dc));
     107  }
     108
    84109  private JSONObject jsonWell;
    85110 
     
    115140    if (jsonWell != null) return jsonWell;
    116141
    117     Extract cdna = getItem();
    118     BioWell well = cdna.getBioWell();
     142    Extract pool = getItem();
     143    BioWell well = pool.getBioWell();
    119144
    120145    if (well != null)
  • extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/servlet/InstallServlet.java

    r1946 r1959  
    251251        jsonChecks.add(checkAnnotationType(dc, Annotationtype.CA_SIZE, 1, null, effectiveOptions, createIfMissing));
    252252        jsonChecks.add(checkAnnotationType(dc, Annotationtype.CA_MOLARITY, 1, null, effectiveOptions, createIfMissing));
     253        jsonChecks.add(checkAnnotationType(dc, Annotationtype.POOL_CONC, 1, null, effectiveOptions, createIfMissing));
     254        jsonChecks.add(checkAnnotationType(dc, Annotationtype.POOL_MOLARITY, 1, null, effectiveOptions, createIfMissing));
    253255
    254256        // Annotation type categories
     
    307309        jsonChecks.add(checkAnnotationTypeCategory(dc, Subtype.LIBRARY, createIfMissing,
    308310            Annotationtype.QUBIT_CONC, Annotationtype.QUBIT_CONC_AFTER_SPEEDVAC, Annotationtype.CA_SIZE, Annotationtype.CA_MOLARITY));
     311
     312        jsonChecks.add(checkAnnotationTypeCategory(dc, Subtype.POOLED_LIBRARY, createIfMissing,
     313            Annotationtype.POOL_MOLARITY, Annotationtype.POOL_CONC));
    309314
    310315        // Plugin definitions and configurations
  • extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/servlet/PoolServlet.java

    r1952 r1959  
    33import java.io.IOException;
    44
    5 import java.util.HashMap;
     5import java.util.Arrays;
    66import java.util.List;
    7 import java.util.Map;
    8 import java.util.regex.Pattern;
    97
    108import javax.servlet.ServletException;
     
    2523import net.sf.basedb.core.DbControl;
    2624import net.sf.basedb.core.Extract;
    27 import net.sf.basedb.core.File;
    28 import net.sf.basedb.core.InvalidDataException;
    2925import net.sf.basedb.core.ItemQuery;
    3026import net.sf.basedb.core.ItemSubtype;
    3127import net.sf.basedb.core.SessionControl;
     28import net.sf.basedb.core.Type;
    3229import net.sf.basedb.core.query.Annotations;
    3330import net.sf.basedb.core.query.Expressions;
     
    4441import net.sf.basedb.util.Values;
    4542import net.sf.basedb.util.error.ThrowableUtil;
    46 import net.sf.basedb.util.parser.FlatFileParser;
    47 import net.sf.basedb.util.parser.Mapper;
    48 import net.sf.basedb.util.parser.FlatFileParser.LineType;
    4943
    5044
     
    5347{
    5448
    55 
     49  /**
     50    Target molarity value when mixing libraries.
     51  */
     52  private static final float TARGET_MOLARITY_IN_POOL = 2f;
     53
     54  /**
     55    µl to use from each lib mixed to 2 nM in the pool
     56  */
     57  private static final float TARGET_VOLUME_IN_POOL_PER_LIB = 5f;
     58 
     59  /**
     60    If the volume to use from the lib is lower than this limit,
     61    we mix a larger amount to begin with, but only use the same target volume
     62    (the extra is left in a temporary plate).
     63  */
     64  private static final float LIMIT_FOR_EXTRA_LARGE_MIX = 2f;
     65 
     66  /**
     67    Percentage to increase the mix when making an extra large mix.
     68    In the common case 1.0 means mixing 10µl instead of 5µl. But, only
     69    5µl is used for the pool and the remaining 5µl is saved in a temporary
     70    location.
     71  */
     72  private static final float EXTRA_LARGE_MIX_FACTOR = 1.0f;
     73 
     74 
    5675  private static final long serialVersionUID = -5652847260721336320L;
    5776
     
    108127        for (BioPlate plate : plates)
    109128        {
    110           JSONObject jsonPlate = new JSONObject();
    111           jsonPlate.put("id", plate.getId());
    112           jsonPlate.put("name", plate.getName());
    113           jsonPlate.put("comments", plate.getDescription());
    114           jsonPlate.put("poolSchema", Annotationtype.POOL_SCHEMA.getAnnotationValue(dc, plate));
    115           jsonPlate.put("barcodeVariant", Annotationtype.BARCODE_VARIANT.getAnnotationValue(dc, plate));
    116           jsonPlates.add(jsonPlate);
     129          jsonPlates.add(getJSONForLibPlate(dc, plate));
    117130        }
    118131        json.put("bioplates", jsonPlates);
    119132      }
     133      else if ("GetLibPlateInfo".equals(cmd))
     134      {
     135        // Load information about a single library bioplate
     136        int libPlateId = Values.getInt(req.getParameter("bioplate"));
     137        dc = sc.newDbControl();
     138        BioPlate libPlate = BioPlate.getById(dc, libPlateId);
     139        json.put("libPlate", getJSONForLibPlate(dc, libPlate));
     140       
     141      }
    120142      else if ("GetLibraryInfoForPlate".equals(cmd))
    121143      {
     144        // Get information about libraries on a single library bioplate
     145        // Calculate mixing volumes for pooling using the target molarity
     146        // and volumes
    122147        int libPlateId = Values.getInt(req.getParameter("bioplate"));
    123148        dc = sc.newDbControl();
     
    139164        {
    140165          lib.loadBioPlateLocation();
    141           lib.loadAnnotations(dc, "molarity", Annotationtype.CA_MOLARITY, null);
    142           lib.loadAnnotations(dc, "originalConc", Annotationtype.QUBIT_CONC, null);
    143           lib.loadAnnotations(dc, "speedVacConc", Annotationtype.QUBIT_CONC_AFTER_SPEEDVAC, null);
    144           lib.setAnnotation("remainingQuantity", lib.getExtract().getRemainingQuantity());
     166          addPoolingCalculationsToLib(dc, lib, null);
    145167          jsonLibs.add(lib.asJSONObject());
    146168        }
    147169
    148170        json.put("libraries", jsonLibs);
     171       
     172        // Send some info about the target molarity and volume used in the pooling calculations
     173        // back to the client for presentation purposes
     174        JSONObject poolInfo = new JSONObject();
     175        poolInfo.put("targetMolarity", TARGET_MOLARITY_IN_POOL);
     176        poolInfo.put("targetVolumePerLib", TARGET_VOLUME_IN_POOL_PER_LIB);
     177        json.put("poolInfo", poolInfo);
    149178      }
    150179      else if ("GetNextAutoGeneratedPoolNames".equals(cmd))
    151180      {
     181        // Get the pool names for the next number of pools to create
    152182        dc = sc.newDbControl();
    153183        int numNames = Values.getInt(req.getParameter("numNames"));
    154184        json.put("names", PooledLibrary.generateNamesForBatch(dc, 1, numNames));
    155 
     185      }
     186      else if ("GetUnprocessedPools".equals(cmd))
     187      {
     188        // Get all PooledLibrary items with no creation date
     189        dc = sc.newDbControl();
     190       
     191        List<PooledLibrary> pools = PooledLibrary.findUnprocessedPools(dc);
     192        JSONArray jsonPools = new JSONArray();
     193        for (PooledLibrary pool : pools)
     194        {
     195          pool.loadAnnotations(dc, "molarity", Annotationtype.POOL_MOLARITY, null);
     196          pool.loadAnnotations(dc, "conc", Annotationtype.POOL_CONC, null);
     197          pool.setAnnotation("remainingQuantity", pool.getExtract().getRemainingQuantity());
     198          jsonPools.add(pool.asJSONObject());
     199         
     200          List<Library> libs = Library.getByPool(dc, pool);
     201          JSONArray jsonLibs = new JSONArray();
     202          for (Library lib : libs)
     203          {
     204            lib.loadBioPlateLocation();
     205            jsonLibs.add(lib.asJSONObject());
     206          }
     207          pool.setAnnotation("libraries", jsonLibs);
     208        }
     209        json.put("pools", jsonPools);
     210      }
     211     
     212      else if ("GetLibraryInfoForPools".equals(cmd))
     213      {
     214        // Get information about the libraries that are pooled in the given PooledLibrary items
     215        dc = sc.newDbControl();
     216        String[] tmp = req.getParameter("pools").split(",");
     217        List<Integer> poolIds = Arrays.asList(Values.getInt(tmp));
     218       
     219        ItemQuery<Extract> poolQuery = Extract.getQuery();
     220        poolQuery.restrict(Restrictions.in(Hql.property("id"), Expressions.parameter("pools", Type.INT)));
     221        poolQuery.setParameter("pools", poolIds, Type.INT);
     222       
     223        List<PooledLibrary> pools = PooledLibrary.toList(poolQuery.list(dc));
     224       
     225        JSONArray jsonPools = new JSONArray();
     226        for (PooledLibrary pool : pools)
     227        {
     228          BioMaterialEvent poolCreationEvent = pool.getExtract().getCreationEvent();
     229          List<Library> libs = Library.getByPool(dc, pool);
     230          JSONArray jsonLibs = new JSONArray();
     231          for (Library lib : libs)
     232          {
     233            lib.loadBioPlateLocation();
     234            addPoolingCalculationsToLib(dc, lib, pool);
     235            jsonLibs.add(lib.asJSONObject());
     236          }
     237         
     238          pool.setAnnotation("libraries", jsonLibs);
     239          pool.loadAnnotations(dc, "molarity", Annotationtype.POOL_MOLARITY, null);
     240          pool.loadAnnotations(dc, "conc", Annotationtype.POOL_CONC, null);
     241          pool.setAnnotation("originalQuantity", pool.getExtract().getOriginalQuantity());
     242          jsonPools.add(pool.asJSONObject());
     243        }
     244        json.put("pools", jsonPools);
     245       
     246        JSONObject poolInfo = new JSONObject();
     247        poolInfo.put("targetMolarity", TARGET_MOLARITY_IN_POOL);
     248        poolInfo.put("targetVolumePerLib", TARGET_VOLUME_IN_POOL_PER_LIB);
     249        json.put("poolInfo", poolInfo);
    156250      }
    157251    }
     
    193287      if ("CreatePools".equals(cmd))
    194288      {
     289        // Create PooledLibrary items from a Library bioplate
    195290        JSONObject jsonReq = (JSONObject)new JSONParser().parse(req.getReader());
    196291        JSONArray jsonPools = (JSONArray)jsonReq.get("pools");
     
    198293        dc = sc.newDbControl();
    199294        ItemSubtype pooledLibraryType = Subtype.POOLED_LIBRARY.load(dc);
    200        
    201         for (int i = 0; i < jsonPools.size(); i++)
     295        ItemSubtype libraryType = Subtype.LIBRARY.load(dc);
     296       
     297        //jsonMessages.add("Target molarity: " + TARGET_MOLARITY_IN_POOL + "; Mix " + TARGET_VOLUME_IN_POOL_PER_LIB + "µl, or " + (TARGET_VOLUME_IN_POOL_PER_LIB * (1+EXTRA_LARGE_MIX_FACTOR)) + " if &lt; " + LIMIT_FOR_EXTRA_LARGE_MIX + "µl");
     298       
     299        for (int poolNo = 0; poolNo < jsonPools.size(); poolNo++)
    202300        {
    203           JSONObject jsonPool = (JSONObject)jsonPools.get(i);
     301          JSONObject jsonPool = (JSONObject)jsonPools.get(poolNo);
    204302          JSONArray jsonLibs = (JSONArray)jsonPool.get("libs");
    205303         
     304          // Create PooledLibrary item
    206305          Extract pool = Extract.getNew(dc);
    207306          pool.setItemSubtype(pooledLibraryType);
     
    210309          BioMaterialEvent poolEvent = pool.getCreationEvent();
    211310         
    212           for (int j = 0; j < jsonLibs.size(); j++)
     311          float poolVolume = 0f;
     312          float poolQuantity = 0f;
     313          float summedPoolMolarity = 0f;
     314         
     315          for (int libNo = 0; libNo < jsonLibs.size(); libNo++)
    213316          {
    214             JSONObject jsonLib = (JSONObject)jsonLibs.get(j);
     317            JSONObject jsonLib = (JSONObject)jsonLibs.get(libNo);
    215318            Number libId = (Number)jsonLib.get("id");
    216319
     320            // Load the library item
    217321            Extract lib = Extract.getById(dc, libId.intValue());
    218             BioMaterialEventSource src = poolEvent.addSource(lib);
    219322           
     323            // Calculate resulting molarity after mixing
     324            Float molarity = (Float)Annotationtype.CA_MOLARITY.getAnnotationValue(dc, lib);
     325            float usedVolumeForPool = ((Number)jsonLib.get("volume")).floatValue();
     326            float usedEbForPool = ((Number)jsonLib.get("eb")).floatValue();
     327           
     328            // Calculate resulting molarity given the used volumes
     329            float molarityForPool = TARGET_MOLARITY_IN_POOL;
     330            if (usedVolumeForPool > TARGET_VOLUME_IN_POOL_PER_LIB)
     331            {
     332              // We can never use more than the target volume
     333              usedVolumeForPool = TARGET_VOLUME_IN_POOL_PER_LIB;
     334              usedEbForPool = 0f;
     335              molarityForPool = molarity;
     336            }
     337            else
     338            {
     339              molarityForPool = molarity * (usedVolumeForPool / (usedVolumeForPool + usedEbForPool));
     340            }
     341                       
     342            // Calculate used quantities, remember that concentration values are stored in ng/µl
    220343            Float originalConc = (Float)Annotationtype.QUBIT_CONC.getAnnotationValue(dc, lib);
    221344            Float speedVacConc = (Float)Annotationtype.QUBIT_CONC_AFTER_SPEEDVAC.getAnnotationValue(dc, lib);
    222345            Float usedConc = speedVacConc == null ? originalConc : speedVacConc;
    223             Float molarity = (Float)Annotationtype.CA_MOLARITY.getAnnotationValue(dc, lib);
    224 
    225             // Get the volume to use from the wizard. This calculated base on the CA_MOLARITY value for each
    226             // sample to give a final concentration of 2nM mixed to 5 or 10µl (for high concentration)
    227             Number usedVolume = (Number)jsonLib.get("volume");
    228             // We never use more than 5µl
    229             Float orginalVolume = usedVolume.floatValue();
    230             if (usedVolume.floatValue() > 5f) usedVolume = 5f;
     346            float usedQuantityForPool = Math.min(usedVolumeForPool * usedConc / 1000, lib.getRemainingQuantity());
     347                       
     348            // Add the library to the pooling event
     349            BioMaterialEventSource poolSrc = poolEvent.addSource(lib);
     350            poolSrc.setUsedQuantity(usedQuantityForPool);
    231351           
    232             // Calculate usedQuantity, Remember that concentration values are stored in ng/µl
    233             Float usedQuantity = Math.min(usedVolume.floatValue() * usedConc / 1000, lib.getRemainingQuantity());
    234             src.setUsedQuantity(usedQuantity);
     352            // Summarize quantity, volumes, molarity for the pool
     353            poolQuantity += usedQuantityForPool;
     354            poolVolume += usedVolumeForPool + usedEbForPool;
     355            summedPoolMolarity += molarityForPool;
    235356           
    236             jsonMessages.add("Using " + Values.formatNumber(usedQuantity*1000, 2) + "/" + Values.formatNumber(orginalVolume*usedConc, 2) +" of " + Values.formatNumber(lib.getOriginalQuantity()*1000,2) + " from " + lib.getName());
     357            //
     358            float extraMixFactor = ((Number)jsonLib.get("extraMixFactor")).floatValue();
     359            float usedQuantityForExtra = 0f;
     360            if (extraMixFactor > 0)
     361            {
     362              // Create 'dil' extract for keeping track of remaining quantity that has been mixed
     363              float usedVolumeForExtra = extraMixFactor * usedVolumeForPool;
     364              usedQuantityForExtra = usedVolumeForExtra * usedConc / 1000;
     365              Extract dil = Extract.getNew(dc);
     366              dil.setItemSubtype(libraryType);
     367              dil.setName(lib.getName()+".dil");
     368              dil.setDescription("Represents the remaining 5µl aliquot after mixing 10µl/2nM solution for some libraries before pooling. Stored at a temporary location.");
     369              BioMaterialEventSource libSrc = dil.getCreationEvent().addSource(lib);
     370              Annotationtype.POOL_MOLARITY.setAnnotationValue(dc, dil, molarityForPool);
     371              Annotationtype.POOL_CONC.setAnnotationValue(dc, dil, 1000 * usedQuantityForExtra / usedVolumeForExtra);
     372              libSrc.setUsedQuantity(usedQuantityForExtra);
     373              dil.setOriginalQuantity(usedQuantityForExtra);
     374              dc.saveItem(dil);
     375            }
     376           
     377            //jsonMessages.add("Using " + Values.formatNumber(usedQuantityForPool*1000, 2) + "+" + Values.formatNumber(usedQuantityForExtra*1000, 2) +"ng of " + Values.formatNumber(lib.getOriginalQuantity()*1000,2) + "ng from " + lib.getName()+"; molarity="+molarity);
    237378          }
    238379         
    239           // TODO - how to calculate the original quantity of the pool
    240           // pool.setOriginalQuantity(????);
    241          
     380          pool.setOriginalQuantity(poolQuantity);
     381          Annotationtype.POOL_CONC.setAnnotationValue(dc, pool, poolQuantity * 1000 / poolVolume);
     382          Annotationtype.POOL_MOLARITY.setAnnotationValue(dc, pool, summedPoolMolarity / jsonLibs.size());
    242383          dc.saveItem(pool);
    243384         
    244           jsonMessages.add("Created '" + pool.getName() + "' from " + jsonLibs.size() + " libraries");
     385          jsonMessages.add("Created '" + pool.getName() + "' from " + jsonLibs.size() + " libraries; pool molarity=" + Values.formatNumber(summedPoolMolarity / jsonLibs.size(), 2)); // conc="+Values.formatNumber(poolQuantity * 1000 / poolVolume, 2) + "ng/µl; quantity="+Values.formatNumber(poolQuantity*1000, 2)+"ng; volume="+Values.formatNumber(poolVolume, 2) + "µl");
    245386        }
    246387       
    247         //dc.commit();
     388        dc.commit();
    248389      }
    249390      json.put("messages", jsonMessages);
     
    265406  }
    266407 
    267   // Parse the Qubit file and return a map extract name -> concentration
    268   private Map<String, String> parseQubitFile(File qubitCsv)
    269     throws IOException
     408 
     409  private void addPoolingCalculationsToLib(DbControl dc, Library lib, PooledLibrary pool)
    270410  {
    271     FlatFileParser ffp = new FlatFileParser();
    272     ffp.setDataHeaderRegexp(Pattern.compile("Well\\tLibrary name\\tConcentration.*"));
    273     ffp.setDataSplitterRegexp(Pattern.compile("\t")); // Split on tab
    274     ffp.setInputStream(qubitCsv.getDownloadStream(0), "UTF-8");
    275    
    276     if (ffp.parseHeaders() != LineType.DATA_HEADER)
    277     {
    278       throw new InvalidDataException("File '" + qubitCsv.getName() + "': Could not find header line starting with 'Well{tab}Library name{tab}Concentration...'");
    279     }
    280 
    281     Mapper nameMapper = ffp.getMapper("\\Library name\\");
    282     Mapper concMapper = ffp.getMapper("\\Concentration\\");
    283 
    284     Map<String, String> result = new HashMap<String, String>();
    285     while (ffp.hasMoreData())
    286     {
    287       FlatFileParser.Data data = ffp.nextData();
    288       String libName = nameMapper.getValue(data);
    289       String conc = concMapper.getValue(data);
    290       result.put(libName, conc);
    291     }
    292    
    293     return result;
     411    // Load original and SpeedVac:ed concentrations
     412    // Note that most libs have not been speedvaced and only have an original concentration
     413    Extract libEx = lib.getExtract();
     414    Float originalConc = (Float)Annotationtype.QUBIT_CONC.getAnnotationValue(dc, libEx);
     415    Float speedVacConc = (Float)Annotationtype.QUBIT_CONC_AFTER_SPEEDVAC.getAnnotationValue(dc, libEx);
     416    lib.setAnnotation("originalConc", originalConc);
     417    lib.setAnnotation("speedVacConc", speedVacConc);
     418   
     419    // Load molarity as calculated from Caliper/Qubit measurements
     420    Float molarity = (Float)Annotationtype.CA_MOLARITY.getAnnotationValue(dc, libEx);
     421    lib.setAnnotation("molarity", molarity);
     422   
     423    // Load remaining quantity of the lib
     424    lib.setAnnotation("remainingQuantity", libEx.getRemainingQuantity());
     425
     426    if (pool != null)
     427    {
     428      // A pool has been "designed", use the quantities as stored in the database
     429      Float usedQuantity = pool.getExtract().getCreationEvent().getUsedQuantity(libEx);
     430      lib.setAnnotation("usedQuantity", usedQuantity);
     431      Float usedConc = speedVacConc == null ? originalConc : speedVacConc;
     432      Float usedVolumeForMix = 1000 * usedQuantity / usedConc;
     433      Float ebVolumeForMix = TARGET_VOLUME_IN_POOL_PER_LIB - usedVolumeForMix;
     434      lib.setAnnotation("volume", usedVolumeForMix);
     435      lib.setAnnotation("eb", ebVolumeForMix);
     436     
     437      // Check if '.dil' exists
     438     
     439      ItemQuery<Extract> query = Extract.getQuery();
     440      query.restrict(Restrictions.eq(Hql.property("name"), Expressions.string(lib.getName()+".dil")));
     441      query.restrict(Restrictions.eq(Hql.property("creationEvent.eventDate"), null));
     442      query.setIncludes(Reggie.INCLUDE_IN_CURRENT_PROJECT);
     443      List<Extract> result = query.list(dc);
     444      if (result.size() == 1)
     445      {
     446        Extract dil = result.get(0);
     447        Float dilQuantity = dil.getOriginalQuantity();
     448        //Float dilConc = (Float)Annotationtype.POOL_CONC.getAnnotationValue(dc, dil);
     449        lib.setAnnotation("extraMixFactor", dilQuantity / usedQuantity);
     450      }
     451     
     452      lib.setAnnotation("dils", result.size());
     453     
     454    }
     455    else
     456    {
     457      // Calculate mix volumes, but do not correct for negative volumes
     458      // due to low concentration (this will be notified in the protocols)
     459      float usedVolumeForMix = TARGET_VOLUME_IN_POOL_PER_LIB * TARGET_MOLARITY_IN_POOL / molarity;
     460      float ebVolumeForMix = TARGET_VOLUME_IN_POOL_PER_LIB - usedVolumeForMix;
     461      lib.setAnnotation("volume", usedVolumeForMix);
     462      lib.setAnnotation("eb", ebVolumeForMix);
     463      // Extra large mix is required if the usedVolume is small due to
     464      // difficulties to pipette the exact amount for small volumes
     465      lib.setAnnotation("extraMixFactor", usedVolumeForMix < LIMIT_FOR_EXTRA_LARGE_MIX ? EXTRA_LARGE_MIX_FACTOR : 0);
     466    }
     467  }
     468 
     469  @SuppressWarnings("unchecked")
     470  private JSONObject getJSONForLibPlate(DbControl dc, BioPlate libPlate)
     471  {
     472    JSONObject jsonPlate = new JSONObject();
     473    jsonPlate.put("id", libPlate.getId());
     474    jsonPlate.put("name", libPlate.getName());
     475    jsonPlate.put("comments", libPlate.getDescription());
     476    jsonPlate.put("poolSchema", Annotationtype.POOL_SCHEMA.getAnnotationValue(dc, libPlate));
     477    jsonPlate.put("barcodeVariant", Annotationtype.BARCODE_VARIANT.getAnnotationValue(dc, libPlate));
     478    return jsonPlate;
    294479  }
    295480}
Note: See TracChangeset for help on using the changeset viewer.