Exemple #1
0
    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'])

            # create input molar percentages
            pcts = calc_pool_pcts(plate_result['comp_vals'],
                                  plate_result['pool_vals'])
            quant_process = QuantificationProcess(
                plate_result['quant-process-id'])
            pool_name = 'Pool from plate %s (%s)' % (
                plate.external_id,
                datetime.now().strftime(quant_process.get_date_format()))
            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))
Exemple #2
0
def create_pool_quantification_process(user, pools):
    concentrations = np.around(np.random.rand(len(pools)), 6)
    concentrations = [{
        'composition': p,
        'concentration': c
    } for p, c in zip(pools, concentrations)]
    return QuantificationProcess.create_manual(user, concentrations)
Exemple #3
0
 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})
Exemple #4
0
    def post(self):
        user = self.current_user
        plates_info = self.get_argument('plates_info')
        water = self.get_argument('water')
        total_vol = self.get_argument('total_vol')
        ng = self.get_argument('ng')
        min_vol = self.get_argument('min_vol')
        max_vol = self.get_argument('max_vol')
        resolution = self.get_argument('resolution')
        reformat = self.get_argument('reformat')

        processes = [[
            plate_id,
            NormalizationProcess.create(
                user,
                QuantificationProcess(quantification_process_id),
                ReagentComposition.from_external_id(water),
                plate_name,
                total_vol=float(total_vol),
                ng=float(ng),
                min_vol=float(min_vol),
                max_vol=float(max_vol),
                resolution=float(resolution),
                reformat=reformat).id
        ] for plate_id, plate_name, quantification_process_id in json_decode(
            plates_info)]

        self.write({'processes': processes})
Exemple #5
0
    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 post(self):
        # We will receive as many files as plates the user has selected
        # The key of the self.request.files dictionary is of the form
        # plate-file-<PLATE_ID> so use the keys to know the plates
        # that we need to quantify
        plates = []
        for key in self.request.files:
            plate_id = key.rsplit('-', 1)[1]
            # The 0 is because for each key we have a single file
            file_content = self.request.files[key][0]['body'].decode('utf-8')
            plate = Plate(plate_id)
            pc = plate.plate_configuration
            concentrations = QuantificationProcess.parse(file_content,
                                                         rows=pc.num_rows,
                                                         cols=pc.num_columns)

            names = np.empty_like(plate.layout, dtype='object')
            blanks = np.zeros_like(plate.layout, dtype=bool)

            # fetch the sample names and whether or not the samples are blanks
            # by default these are set to be None and False.
            for i, full_row in enumerate(plate.layout):
                for j, well in enumerate(full_row):

                    # some wells have no compositions at all so skip those
                    if well is None:
                        continue
                    comp = well.composition

                    # cache the sample compositions to avoid extra intermediate
                    # queries
                    if isinstance(comp, GDNAComposition):
                        smp = comp.sample_composition
                    elif isinstance(comp, (CompressedGDNAComposition,
                                           LibraryPrep16SComposition)):
                        smp = comp.gdna_composition.sample_composition
                    elif isinstance(comp, LibraryPrepShotgunComposition):
                        smp = comp.normalized_gdna_composition\
                            .compressed_gdna_composition.gdna_composition\
                            .sample_composition
                    else:
                        raise ValueError('This composition type is not '
                                         'supported')

                    blanks[i][j] = smp.sample_composition_type == 'blank'
                    names[i][j] = smp.sample_id

            plates.append({
                'plate_name': plate.external_id,
                'plate_id': plate_id,
                'concentrations': concentrations.tolist(),
                'names': names.tolist(),
                'blanks': blanks.tolist(),
                'type': plate.process._process_type
            })

        self.render('quantification.html', plates=plates)
    def post(self):
        plates_info = json_decode(self.get_argument('plates-info'))
        processes = []
        for pinfo in plates_info:
            plate = Plate(pinfo['plate_id'])
            concentrations = np.asarray(pinfo['concentrations'])

            processes.append(QuantificationProcess.create(
                self.current_user, plate, concentrations).id)

        self.write({'processes': processes})
Exemple #8
0
 def post(self):
     plate_id = self.get_argument('plate-select')
     # Magic number 0 -> there is only 1 file attached
     file_content = self.request.files['plate-reader-fp'][0]['body'].decode(
         'utf-8')
     concentrations = QuantificationProcess.parse(file_content)
     plate = Plate(plate_id)
     self.render('quantification.html',
                 concentrations=concentrations.tolist(),
                 plate_name=plate.external_id,
                 plate_id=plate.id,
                 plate_conf=plate.plate_configuration.description)
    def post(self):
        # We will receive as many files as plates the user has selected
        # The key of the self.request.files dictionary is of the form
        # plate-file-<PLATE_ID> so use the keys to know the plates
        # that we need to quantify
        plates = []
        for key in self.request.files:
            plate_id = key.rsplit('-', 1)[1]
            # The 0 is because for each key we have a single file
            file_content = self.request.files[key][0]['body'].decode('utf-8')
            plate = Plate(plate_id)
            pc = plate.plate_configuration
            concentrations = QuantificationProcess.parse(
                file_content, rows=pc.num_rows, cols=pc.num_columns)
            plates.append({'plate_name': plate.external_id,
                           'plate_id': plate_id,
                           'concentrations': concentrations.tolist()})

        self.render('quantification.html', plates=plates)
Exemple #10
0
def create_quantification_process(user, plate):
    plate_config = plate.plate_configuration
    concentrations = np.around(
        np.random.rand(plate_config.num_rows, plate_config.num_columns), 6)
    quant_process = QuantificationProcess.create(user, plate, concentrations)
    return quant_process
Exemple #11
0
    def test_properties(self):
        # Plate 21 - Defined in the test DB
        tester = Plate(21)
        self.assertEqual(tester.external_id, 'Test plate 1')
        self.assertEqual(tester.plate_configuration, PlateConfiguration(1))
        self.assertFalse(tester.discarded)
        self.assertIsNone(tester.notes)
        obs_layout = tester.layout
        self.assertEqual(len(obs_layout), 8)
        for row in obs_layout:
            self.assertEqual(len(row), 12)
        self.assertEqual(tester.studies, {Study(1)})
        self.assertIsNone(tester.quantification_process)
        self.assertEqual(tester.process, SamplePlatingProcess(10))

        # Test changing the name of the plate
        tester.external_id = 'Some new name'
        self.assertEqual(tester.external_id, 'Some new name')
        tester.external_id = 'Test plate 1'
        self.assertEqual(tester.external_id, 'Test plate 1')

        self.assertEqual(
            Plate(23).quantification_process, QuantificationProcess(1))
        self.assertEqual(Plate(22).process, GDNAExtractionProcess(1))

        exp = {
            '1.SKB1.640202': [
                Well(3073),
                Well(3253),
                Well(3433),
                Well(3613),
                Well(3793),
                Well(3973)
            ],
            '1.SKB2.640194': [
                Well(3088),
                Well(3268),
                Well(3448),
                Well(3628),
                Well(3808),
                Well(3988)
            ],
            '1.SKB3.640195': [
                Well(3103),
                Well(3283),
                Well(3463),
                Well(3643),
                Well(3823),
                Well(4003)
            ],
            '1.SKB4.640189': [
                Well(3118),
                Well(3298),
                Well(3478),
                Well(3658),
                Well(3838),
                Well(4018)
            ],
            '1.SKB5.640181': [
                Well(3133),
                Well(3313),
                Well(3493),
                Well(3673),
                Well(3853),
                Well(4033)
            ],
            '1.SKB6.640176': [
                Well(3148),
                Well(3328),
                Well(3508),
                Well(3688),
                Well(3868),
                Well(4048)
            ],
            '1.SKB7.640196': [
                Well(3163),
                Well(3343),
                Well(3523),
                Well(3703),
                Well(3883),
                Well(4063)
            ],
            '1.SKB8.640193': [
                Well(3178),
                Well(3358),
                Well(3538),
                Well(3718),
                Well(3898),
                Well(4078)
            ],
            '1.SKB9.640200': [
                Well(3193),
                Well(3373),
                Well(3553),
                Well(3733),
                Well(3913),
                Well(4093)
            ],
            '1.SKD1.640179': [
                Well(3208),
                Well(3388),
                Well(3568),
                Well(3748),
                Well(3928),
                Well(4108)
            ],
            '1.SKD2.640178': [
                Well(3223),
                Well(3403),
                Well(3583),
                Well(3763),
                Well(3943),
                Well(4123)
            ],
            '1.SKD3.640198': [
                Well(3238),
                Well(3418),
                Well(3598),
                Well(3778),
                Well(3958),
                Well(4138)
            ]
        }
        self.assertEqual(tester.duplicates, exp)
Exemple #12
0
    def test_properties(self):
        # Plate 21 - Defined in the test DB
        tester = Plate(21)
        self.assertEqual(tester.external_id, 'Test plate 1')
        self.assertEqual(tester.plate_configuration, PlateConfiguration(1))
        self.assertFalse(tester.discarded)
        tester.discarded = True
        self.assertTrue(tester.discarded)
        self.assertIsNone(tester.notes)
        obs_layout = tester.layout
        self.assertEqual(len(obs_layout), 8)
        for row in obs_layout:
            self.assertEqual(len(row), 12)
        self.assertEqual(tester.studies, {Study(1)})
        self.assertIsNone(tester.quantification_process)
        self.assertEqual(tester.process, SamplePlatingProcess(10))

        # Test changing the name of the plate
        tester.external_id = 'Some new name'
        self.assertEqual(tester.external_id, 'Some new name')
        tester.external_id = 'Test plate 1'
        self.assertEqual(tester.external_id, 'Test plate 1')

        self.assertEqual(
            Plate(23).quantification_process, QuantificationProcess(1))
        self.assertEqual(Plate(22).process, GDNAExtractionProcess(1))

        exp = {
            '1.SKB1.640202': [[Well(3073), '1.SKB1.640202.21.A1'],
                              [Well(3253), '1.SKB1.640202.21.B1'],
                              [Well(3433), '1.SKB1.640202.21.C1'],
                              [Well(3613), '1.SKB1.640202.21.D1'],
                              [Well(3793), '1.SKB1.640202.21.E1'],
                              [Well(3973), '1.SKB1.640202.21.F1']],
            '1.SKB2.640194': [[Well(3088), '1.SKB2.640194.21.A2'],
                              [Well(3268), '1.SKB2.640194.21.B2'],
                              [Well(3448), '1.SKB2.640194.21.C2'],
                              [Well(3628), '1.SKB2.640194.21.D2'],
                              [Well(3808), '1.SKB2.640194.21.E2'],
                              [Well(3988), '1.SKB2.640194.21.F2']],
            '1.SKB3.640195': [[Well(3103), '1.SKB3.640195.21.A3'],
                              [Well(3283), '1.SKB3.640195.21.B3'],
                              [Well(3463), '1.SKB3.640195.21.C3'],
                              [Well(3643), '1.SKB3.640195.21.D3'],
                              [Well(3823), '1.SKB3.640195.21.E3'],
                              [Well(4003), '1.SKB3.640195.21.F3']],
            '1.SKB4.640189': [[Well(3118), '1.SKB4.640189.21.A4'],
                              [Well(3298), '1.SKB4.640189.21.B4'],
                              [Well(3478), '1.SKB4.640189.21.C4'],
                              [Well(3658), '1.SKB4.640189.21.D4'],
                              [Well(3838), '1.SKB4.640189.21.E4'],
                              [Well(4018), '1.SKB4.640189.21.F4']],
            '1.SKB5.640181': [[Well(3133), '1.SKB5.640181.21.A5'],
                              [Well(3313), '1.SKB5.640181.21.B5'],
                              [Well(3493), '1.SKB5.640181.21.C5'],
                              [Well(3673), '1.SKB5.640181.21.D5'],
                              [Well(3853), '1.SKB5.640181.21.E5'],
                              [Well(4033), '1.SKB5.640181.21.F5']],
            '1.SKB6.640176': [[Well(3148), '1.SKB6.640176.21.A6'],
                              [Well(3328), '1.SKB6.640176.21.B6'],
                              [Well(3508), '1.SKB6.640176.21.C6'],
                              [Well(3688), '1.SKB6.640176.21.D6'],
                              [Well(3868), '1.SKB6.640176.21.E6'],
                              [Well(4048), '1.SKB6.640176.21.F6']],
            '1.SKB7.640196': [[Well(3163), '1.SKB7.640196.21.A7'],
                              [Well(3343), '1.SKB7.640196.21.B7'],
                              [Well(3523), '1.SKB7.640196.21.C7'],
                              [Well(3703), '1.SKB7.640196.21.D7'],
                              [Well(3883), '1.SKB7.640196.21.E7'],
                              [Well(4063), '1.SKB7.640196.21.F7']],
            '1.SKB8.640193': [[Well(3178), '1.SKB8.640193.21.A8'],
                              [Well(3358), '1.SKB8.640193.21.B8'],
                              [Well(3538), '1.SKB8.640193.21.C8'],
                              [Well(3718), '1.SKB8.640193.21.D8'],
                              [Well(3898), '1.SKB8.640193.21.E8'],
                              [Well(4078), '1.SKB8.640193.21.F8']],
            '1.SKB9.640200': [[Well(3193), '1.SKB9.640200.21.A9'],
                              [Well(3373), '1.SKB9.640200.21.B9'],
                              [Well(3553), '1.SKB9.640200.21.C9'],
                              [Well(3733), '1.SKB9.640200.21.D9'],
                              [Well(3913), '1.SKB9.640200.21.E9'],
                              [Well(4093), '1.SKB9.640200.21.F9']],
            '1.SKD1.640179': [[Well(3208), '1.SKD1.640179.21.A10'],
                              [Well(3388), '1.SKD1.640179.21.B10'],
                              [Well(3568), '1.SKD1.640179.21.C10'],
                              [Well(3748), '1.SKD1.640179.21.D10'],
                              [Well(3928), '1.SKD1.640179.21.E10'],
                              [Well(4108), '1.SKD1.640179.21.F10']],
            '1.SKD2.640178': [[Well(3223), '1.SKD2.640178.21.A11'],
                              [Well(3403), '1.SKD2.640178.21.B11'],
                              [Well(3583), '1.SKD2.640178.21.C11'],
                              [Well(3763), '1.SKD2.640178.21.D11'],
                              [Well(3943), '1.SKD2.640178.21.E11'],
                              [Well(4123), '1.SKD2.640178.21.F11']],
            '1.SKD3.640198': [[Well(3238), '1.SKD3.640198.21.A12'],
                              [Well(3418), '1.SKD3.640198.21.B12'],
                              [Well(3598), '1.SKD3.640198.21.C12'],
                              [Well(3778), '1.SKD3.640198.21.D12'],
                              [Well(3958), '1.SKD3.640198.21.E12'],
                              [Well(4138), '1.SKD3.640198.21.F12']]
        }
        self.assertEqual(tester.duplicates, exp)
        self.assertEqual(tester.unknown_samples, [])
        exp = tester.get_well(1, 1)
        exp.composition.update('Unknown')
        self.assertEqual(tester.unknown_samples, [exp])
        exp.composition.update('1.SKB1.640202')
Exemple #13
0
    def test_properties(self):
        # Plate 21 - Defined in the test DB
        tester = Plate(21)
        self.assertEqual(tester.external_id, 'Test plate 1')
        self.assertEqual(tester.plate_configuration, PlateConfiguration(1))
        self.assertFalse(tester.discarded)
        tester.discarded = True
        self.assertTrue(tester.discarded)
        self.assertIsNone(tester.notes)
        obs_layout = tester.layout
        self.assertEqual(len(obs_layout), 8)
        for row in obs_layout:
            self.assertEqual(len(row), 12)
        self.assertEqual(tester.studies, {Study(1)})
        self.assertListEqual(tester.quantification_processes, [])
        self.assertEqual(tester.process, SamplePlatingProcess(10))

        # Test changing the name of the plate
        tester.external_id = 'Some new name'
        self.assertEqual(tester.external_id, 'Some new name')
        tester.external_id = 'Test plate 1'
        self.assertEqual(tester.external_id, 'Test plate 1')

        self.assertEqual(len(Plate(23).quantification_processes), 1)
        self.assertEqual(
            Plate(23).quantification_processes[0], QuantificationProcess(1))
        self.assertEqual(Plate(22).process, GDNAExtractionProcess(1))

        exp = {
            '1.SKB1.640202': [[Well(3073), '1.SKB1.640202.21.A1'],
                              [Well(3121), '1.SKB1.640202.21.A2'],
                              [Well(3169), '1.SKB1.640202.21.A3'],
                              [Well(3217), '1.SKB1.640202.21.A4'],
                              [Well(3265), '1.SKB1.640202.21.A5'],
                              [Well(3313), '1.SKB1.640202.21.A6'],
                              [Well(3361), '1.SKB1.640202.21.A7'],
                              [Well(3409), '1.SKB1.640202.21.A8'],
                              [Well(3457), '1.SKB1.640202.21.A9'],
                              [Well(3505), '1.SKB1.640202.21.A10'],
                              [Well(3553), '1.SKB1.640202.21.A11'],
                              [Well(3601), '1.SKB1.640202.21.A12']],
            '1.SKB2.640194': [[Well(3079), '1.SKB2.640194.21.B1'],
                              [Well(3127), '1.SKB2.640194.21.B2'],
                              [Well(3175), '1.SKB2.640194.21.B3'],
                              [Well(3223), '1.SKB2.640194.21.B4'],
                              [Well(3271), '1.SKB2.640194.21.B5'],
                              [Well(3319), '1.SKB2.640194.21.B6'],
                              [Well(3367), '1.SKB2.640194.21.B7'],
                              [Well(3415), '1.SKB2.640194.21.B8'],
                              [Well(3463), '1.SKB2.640194.21.B9'],
                              [Well(3511), '1.SKB2.640194.21.B10'],
                              [Well(3559), '1.SKB2.640194.21.B11'],
                              [Well(3607), '1.SKB2.640194.21.B12']],
            '1.SKB3.640195': [[Well(3085), '1.SKB3.640195.21.C1'],
                              [Well(3133), '1.SKB3.640195.21.C2'],
                              [Well(3181), '1.SKB3.640195.21.C3'],
                              [Well(3229), '1.SKB3.640195.21.C4'],
                              [Well(3277), '1.SKB3.640195.21.C5'],
                              [Well(3325), '1.SKB3.640195.21.C6'],
                              [Well(3373), '1.SKB3.640195.21.C7'],
                              [Well(3421), '1.SKB3.640195.21.C8'],
                              [Well(3469), '1.SKB3.640195.21.C9'],
                              [Well(3517), '1.SKB3.640195.21.C10'],
                              [Well(3565), '1.SKB3.640195.21.C11'],
                              [Well(3613), '1.SKB3.640195.21.C12']],
            '1.SKB4.640189': [[Well(3091), '1.SKB4.640189.21.D1'],
                              [Well(3139), '1.SKB4.640189.21.D2'],
                              [Well(3187), '1.SKB4.640189.21.D3'],
                              [Well(3235), '1.SKB4.640189.21.D4'],
                              [Well(3283), '1.SKB4.640189.21.D5'],
                              [Well(3331), '1.SKB4.640189.21.D6'],
                              [Well(3379), '1.SKB4.640189.21.D7'],
                              [Well(3427), '1.SKB4.640189.21.D8'],
                              [Well(3475), '1.SKB4.640189.21.D9'],
                              [Well(3523), '1.SKB4.640189.21.D10'],
                              [Well(3571), '1.SKB4.640189.21.D11'],
                              [Well(3619), '1.SKB4.640189.21.D12']],
            '1.SKB5.640181': [[Well(3097), '1.SKB5.640181.21.E1'],
                              [Well(3145), '1.SKB5.640181.21.E2'],
                              [Well(3193), '1.SKB5.640181.21.E3'],
                              [Well(3241), '1.SKB5.640181.21.E4'],
                              [Well(3289), '1.SKB5.640181.21.E5'],
                              [Well(3337), '1.SKB5.640181.21.E6'],
                              [Well(3385), '1.SKB5.640181.21.E7'],
                              [Well(3433), '1.SKB5.640181.21.E8'],
                              [Well(3481), '1.SKB5.640181.21.E9'],
                              [Well(3529), '1.SKB5.640181.21.E10'],
                              [Well(3577), '1.SKB5.640181.21.E11'],
                              [Well(3625), '1.SKB5.640181.21.E12']],
            '1.SKB6.640176': [[Well(3103), '1.SKB6.640176.21.F1'],
                              [Well(3151), '1.SKB6.640176.21.F2'],
                              [Well(3199), '1.SKB6.640176.21.F3'],
                              [Well(3247), '1.SKB6.640176.21.F4'],
                              [Well(3295), '1.SKB6.640176.21.F5'],
                              [Well(3343), '1.SKB6.640176.21.F6'],
                              [Well(3391), '1.SKB6.640176.21.F7'],
                              [Well(3439), '1.SKB6.640176.21.F8'],
                              [Well(3487), '1.SKB6.640176.21.F9'],
                              [Well(3535), '1.SKB6.640176.21.F10'],
                              [Well(3583), '1.SKB6.640176.21.F11'],
                              [Well(3631), '1.SKB6.640176.21.F12']]
        }
        self.assertEqual(tester.duplicates, exp)
        self.assertEqual(tester.unknown_samples, [])
        exp = tester.get_well(1, 1)
        exp.composition.update('Unknown')
        self.assertEqual(tester.unknown_samples, [exp])
        exp.composition.update('1.SKB1.640202')

        # test that the quantification_processes attribute correctly
        # orders multiple processes in order from oldest to newest
        tester2 = Plate(26)
        self.assertEqual(len(tester2.quantification_processes), 2)
        self.assertEqual(
            tester2.quantification_processes[0].date,
            datetime.strptime("2017-10-25 19:10:25-0700",
                              '%Y-%m-%d %H:%M:%S%z'))
        self.assertEqual(
            tester2.quantification_processes[1].date,
            datetime.strptime("2017-10-26 03:10:25-0700",
                              '%Y-%m-%d %H:%M:%S%z'))
Exemple #14
0
    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