def get(self, process_id): try: process = PoolingProcess(int(process_id)) except LabmanUnknownIdError: raise HTTPError(404, reason='PoolingProcess %s does not exist' % process_id) text = process.generate_pool_file() plate_names_set = {x[0].container.plate.external_id for x in process.components} # Note that PoolingProcess objects (what `process` is above) definitely # *can* validly have components from multiple plates: a user could # chose to make a "plate pool" from more than one amplicon library prep # plate. However, as of 10/09/2018, the wet lab apparently currently # chooses not to do this, and instead chooses to make one pool per # library prep plate. Given this self-imposed limitation, they expect # to be able to have the (one-and-only) library plate name embedded in # the name of the resulting normpool file. This # *file naming convention* won't work--or at least, won't work as they # expect it to--if there are multiple plates represented in the pool, # so if that happens we generate an error below, at the point where the # *file name* is generated. If they decide they want to allow # themselves to make plate pools from multiple plates, all they need to # do is decide on a more flexible naming convention, and # we can change this naming code and remove this error condition. if len(plate_names_set) > 1: raise ValueError("Unable to generate normpool file name for pool " "based on more than one plate: " + ", ".join(str(x) for x in plate_names_set)) plate_name = plate_names_set.pop() name_pieces = [plate_name, "normpool"] self.deliver_text(name_pieces, process, text, extension="csv")
def post(self): pool_name = self.get_argument('pool_name') pools_info = json_decode(self.get_argument('pools_info')) concentrations = [] input_compositions = [] for p_info in pools_info: pool_comp = PoolComposition(p_info['pool_id']) concentrations.append({ 'composition': pool_comp, 'concentration': p_info['concentration'] }) input_compositions.append({ 'composition': pool_comp, 'input_volume': p_info['volume'], 'percentage_of_output': p_info['percentage'] }) # Create the quantification process (DNA conc) q_process = QuantificationProcess.create_manual( self.current_user, concentrations) # Create the pool - Magic number 5 - > the volume for this poolings # is always 5 according to the wet lab. p_process = PoolingProcess.create(self.current_user, q_process, pool_name, 5, input_compositions, { "function": "amplicon_pool", "parameters": {} }) self.write({'process': p_process.id})
def post(self): plates_info = json_decode(self.get_argument('plates-info')) results = [] for pinfo in plates_info: plate_result = self._compute_pools(pinfo) plate = Plate(plate_result['plate_id']) pool_name = 'Pool from plate %s (%s)' % ( plate.external_id, datetime.now().strftime('%Y-%m-%d %H:%M:%S')) # create input molar percentages pcts = calc_pool_pcts(plate_result['comp_vals'], plate_result['pool_vals']) quant_process = plate.quantification_process input_compositions = [] for comp, _, _ in quant_process.concentrations: well = comp.container row = well.row - 1 column = well.column - 1 input_compositions.append( {'composition': comp, 'input_volume': plate_result['pool_vals'][row][column], 'percentage_of_output': pcts[row][column]}) robot = (Equipment(plate_result['robot']) if plate_result['robot'] is not None else None) process = PoolingProcess.create( self.current_user, quant_process, pool_name, plate_result['pool_vals'].sum(), input_compositions, plate_result['func_data'], robot=robot, destination=plate_result['destination']) results.append({'plate-id': plate.id, 'process-id': process.id}) self.write(json_encode(results))
def post(self): plate_id = self.get_argument('plate-id') concentrations = json_decode(self.get_argument('concentrations')) concentrations = np.asarray(concentrations) plate = Plate(plate_id) q_process = QuantificationProcess.create(self.current_user, plate, concentrations) pool_name = 'Pool - %s' % plate.external_id input_compositions = [] concentrations = q_process.concentrations total_vol = 0 for conc in concentrations: in_vol = conc[1] total_vol += in_vol input_compositions.append({ 'composition': conc[0], 'input_volume': in_vol, 'percentage_of_output': in_vol }) for ic in input_compositions: ic['percentage_of_output'] = ic['percentage_of_output'] / total_vol process = PoolingProcess.create(self.current_user, q_process, pool_name, total_vol, input_compositions) self.write({'process': process.id})
def create_pools_pool_process(user, quant_process, pools): input_compositions = [ {'composition': p, 'input_volume': 1, 'percentage_of_output': 1/9.0} for p in pools] pool_process = PoolingProcess.create( user, quant_process, 'New pool name %s' % datetime.now(), 5, input_compositions, {"function": "amplicon_pool", "parameters": {}}) return pool_process
def test_properties(self): tester = Tube(7) self.assertEqual(tester.external_id, 'Test Pool from Plate 1') self.assertFalse(tester.discarded) self.assertEqual(tester.remaining_volume, 96) self.assertIsNone(tester.notes) self.assertEqual(tester.latest_process, PoolingProcess(1)) self.assertEqual(tester.container_id, 3079) self.assertEqual(tester.composition, PoolComposition(1))
def get(self): plate_ids = self.get_arguments('plate_id') process_id = self.get_argument('process_id', None) input_plate = None pool_func_data = None pool_values = [] pool_blanks = [] plate_names = [] plate_type = None if process_id is not None: try: process = PoolingProcess(process_id) except LabmanUnknownIdError: raise HTTPError(404, reason="Pooling process %s doesn't exist" % process_id) plate = process.components[0][0].container.plate input_plate = plate.id pool_func_data = process.pooling_function_data _, pool_values, pool_blanks, plate_names = \ make_2D_arrays(plate, plate.quantification_process) pool_values = pool_values.tolist() pool_blanks = pool_blanks.tolist() plate_names = plate_names.tolist() if pool_func_data['function'] == 'amplicon': pool_func_data['parameters']['epmotion-'] = process.robot.id pool_func_data['parameters'][ 'dest-tube-'] = process.destination elif len(plate_ids) > 0: content_types = { type(Plate(pid).get_well(1, 1).composition) for pid in plate_ids } if len(content_types) > 1: raise HTTPError(400, reason='Plates contain different types ' 'of compositions') plate_type = ('16S library prep' if content_types.pop() == LibraryPrep16SComposition else 'shotgun library prep') epmotions = Equipment.list_equipment('EpMotion') self.render('library_pooling.html', plate_ids=plate_ids, epmotions=epmotions, pool_params=HTML_POOL_PARAMS, input_plate=input_plate, pool_func_data=pool_func_data, process_id=process_id, pool_values=pool_values, plate_type=plate_type, pool_blanks=pool_blanks, plate_names=plate_names)
def get(self, process_id): try: process = PoolingProcess(int(process_id)) except LabmanUnknownIdError: raise HTTPError(404, reason='PoolingProcess %s does not exist' % process_id) text = process.generate_pool_file() filename = 'PoolFile_%s_%s.csv' % ( re.sub('[^0-9a-zA-Z\-\_]+', '_', process.pool.container.external_id), process.id) self.set_header('Content-Type', 'text/csv') self.set_header('Expires', '0') self.set_header('Cache-Control', 'no-cache') self.set_header('Content-Disposition', 'attachment; filename=' '%s.csv' % filename) self.write(text) self.finish()
def create_plate_pool_process(user, quant_process, plate, func_data): input_compositions = [] echo = Equipment(8) for well in chain.from_iterable(plate.layout): if well is not None: input_compositions.append({ 'composition': well.composition, 'input_volume': 1, 'percentage_of_output': 1/9.0}) pool_process = PoolingProcess.create( user, quant_process, 'New test pool name %s' % datetime.now(), 4, input_compositions, func_data, robot=echo) return pool_process
def get(self): pool_ids = self.get_arguments('pool_id') process_id = self.get_argument('process_id', None) pool_comp_info = None pool_name = None if process_id is not None: try: process = PoolingProcess(process_id) except LabmanUnknownIdError: raise HTTPError(404, reason="Pooling process %s doesn't exist" % process_id) pool_comp_info = [[p.id, p.raw_concentration] for p, _ in process.components] pool_name = process.pool.container.external_id self.render('pool_pooling.html', pool_ids=pool_ids, process_id=process_id, pool_comp_info=pool_comp_info, pool_name=pool_name)
def _compute_pools(self, plate_info): plate_id = plate_info['plate-id'] func_name = plate_info['pool-func'] plate_type = plate_info['plate-type'] quant_process_id = plate_info['quant-process-id'] func_info = POOL_FUNCS[func_name] function = func_info['function'] plate = Plate(plate_id) quant_process = QuantificationProcess(quant_process_id) # make params dictionary for function params = {} for arg, pfx in func_info['parameters']: param_key = '%s%s' % (pfx, plate_id) if param_key not in plate_info: raise HTTPError( 400, reason='Missing parameter %s' % param_key) # empty strings are sent when we have disabled inputs. # we are testing for them explicitly where expected. if plate_info[param_key] != '': params[arg] = float(plate_info[param_key]) else: params[arg] = plate_info[param_key] # compute molar concentrations quant_process.compute_concentrations(size=params['size']) # calculate pooled values raw_concs, comp_concs, comp_blanks, \ plate_names = make_2D_arrays(plate, quant_process) if plate_type == '16S library prep': # for 16S, we calculate each sample independently params['total_each'] = True # constant accounts for both concentrations (ng/uL) and volumes # (uL) in the same unit params['vol_constant'] = 1 pool_vals = function(raw_concs, **params) if plate_type == 'shotgun library prep': # for shotgun, we calculate to a target total pool size params['total_each'] = False # constant handles volumes in nanoliters and concentrations in # molarity (mol / L) params['vol_constant'] = 10 ** 9 pool_vals = function(comp_concs, **params) # if adjust blank volume, do that if params['blank_vol'] != '': pool_vals = PoolingProcess.adjust_blank_vols(pool_vals, comp_blanks, params['blank_vol']) # if only pool some blanks, do that if params['blank_num'] != '': pool_vals = PoolingProcess.select_blanks(pool_vals, raw_concs, comp_blanks, int(params['blank_num'])) # estimate pool volume and concentration total_c, total_v = PoolingProcess.estimate_pool_conc_vol(pool_vals, comp_concs) # store output values output = {} output['func_data'] = {'function': func_name, 'parameters': params} output['raw_vals'] = raw_concs output['comp_vals'] = comp_concs output['pool_vals'] = pool_vals output['pool_blanks'] = comp_blanks.tolist() output['plate_names'] = plate_names.tolist() output['plate_id'] = plate_id output['destination'] = params['destination'] output['robot'] = params['robot'] output['blank_vol'] = params['blank_vol'] output['blank_num'] = params['blank_num'] output['total_conc'] = total_c output['total_vol'] = total_v output['quant-process-id'] = quant_process_id return output