Пример #1
0
//  TASK: 	define output plates
// INPUT: 	"output_platetype", "outputs"
//OUTPUT: 	"output_plates"      -- these each have components in wells
//		"output_assignments" -- map with arrays of assignment strings, i.e. {tea: [plate1:A:1, plate1:A:2...] }etc.
func output_plate_setup(request *LHRequest) *LHRequest {
	//(map[string]*wtype.LHPlate, map[string][]string) {
	output_platetype := (*request).Output_platetype
	if output_platetype == nil || output_platetype.ID == "" {
		wutil.Error(errors.New("plate_setup: No output plate type defined"))
	}

	if (*request).Output_major_group_layouts == nil {
		wutil.Error(errors.New("plate setup: Output major groups undefined"))
	}

	output_plates := (*request).Output_plates

	if len(output_plates) == 0 {
		output_plates = make(map[string]*wtype.LHPlate, len(request.Output_major_group_layouts))
	}

	// just assign based on number of groups

	opl := request.Output_plate_layout

	for i := 0; i < len(request.Output_major_group_layouts); i++ {
		//p := wtype.New_Plate(request.Output_platetype)
		p := factory.GetPlateByType(request.Output_platetype.Type)
		output_plates[p.ID] = p
		opl[i] = p.ID
		name := fmt.Sprintf("Output_plate_%d", i+1)
		p.PlateName = name
	}

	(*request).Output_plate_layout = opl
	(*request).Output_plates = output_plates
	return request
}
Пример #2
0
func (w *LHWell) Add(p Physical) {
	switch t := p.(type) {
	default:
		wutil.Error(errors.New(fmt.Sprintf("LHWell: Cannot add type %T", t)))
	case *LHSolution:
		// do something
	case *LHComponent:
		w.WContents = append(w.WContents, p.(*LHComponent))
		w.Currvol += p.(*LHComponent).Vol
		p.(*LHComponent).LContainer = w
	}

}
Пример #3
0
//  TASK: 	Determine number of tip boxes of each type
// INPUT: 	instructions
//OUTPUT: 	arrays of tip boxes
func (lh *Liquidhandler) Tip_box_setup(request *LHRequest) *LHRequest {
	tip_box_type := (*request).Tip_Type
	if tip_box_type == nil || tip_box_type.ID == "" {
		wutil.Error(errors.New("tip_box_setup: No tip_box type defined"))
	}
	tip_boxes := (*request).Tips
	if len(tip_boxes) == 0 {
		tip_boxes = make([]*wtype.LHTipbox, 0)
	}

	// the instructions are generated at this point so we just need to go through and count the tips used
	// of each type

	instrx := request.Instructions

	ntips := make(map[string]int)

	for _, ins := range instrx {
		if ins.InstructionType() == lhdriver.LOD {
			ttype := ins.GetParameter("TIPTYPE").([]string)[0]
			ntips[ttype] += ins.GetParameter("MULTI").(int)
		}
	}

	for tiptype, ntip := range ntips {
		// need to make sure the names match up here
		tbt := factory.GetTipByType(tiptype)
		ntbx := ntip/tbt.NTips + 1
		for i := 0; i < ntbx; i++ {
			tbt2 := factory.GetTipByType(tiptype)
			tip_boxes = append(tip_boxes, tbt2)
		}
	}

	(*request).Tips = tip_boxes

	// need to fix the tip situation in the properties structure

	lh.Properties.RemoveTipBoxes()

	for _, tb := range tip_boxes {
		lh.Properties.AddTipBox(tb)
	}

	return request
}
Пример #4
0
func (lhc *LHComponent) Sample(v wunit.Volume) Liquid {
	// need to jig around with units a bit here
	// Should probably just make Vunit, Cunit etc. wunits anyway
	meas := wunit.ConcreteMeasurement{lhc.Vol, wunit.ParsePrefixedUnit(lhc.Vunit)}

	// we need some logic potentially

	if v.SIValue() > meas.SIValue() {
		wutil.Error(errors.New(fmt.Sprintf("LHComponent ID: %s Not enough volume for sample", lhc.ID)))
	} else if v.SIValue() == meas.SIValue() {
		return lhc
	}
	smp := CopyLHComponent(lhc)
	// need a convention here

	smp.Vol = v.RawValue()
	smp.Vunit = v.Unit().PrefixedSymbol()
	meas.Subtract(&v.ConcreteMeasurement)
	lhc.Vol = meas.RawValue()
	return smp
}
Пример #5
0
func AdvancedExecutionPlanner(request *LHRequest, parameters *liquidhandling.LHProperties) *LHRequest {
	// in the first instance we assume this is done component-wise
	// we also need to identify dependencies, i.e. if certain components
	// are only available after other actions
	// this will only work if the components to be added are to go in the same order

	// get the layout groups

	minorlayoutgroups := request.Output_minor_group_layouts
	ass := request.Output_assignments
	inass := request.Input_assignments
	output_solutions := request.Output_solutions
	input_plates := request.Input_plates
	output_plate_layout := request.Output_plate_layout

	plate_lookup := request.Plate_lookup

	// highly inelegant... we should swap Tip Box Setup
	// around to take place after, then this whole thing
	// is a non-issue
	tt := make([]*wtype.LHTip, 1)
	tt[0] = request.Tip_Type.Tiptype
	parameters.Tips = tt

	instructions := liquidhandling.NewRobotInstructionSet(nil)
	// need to deal with solutions

	order := request.Input_order

	for _, name := range order {
		//fmt.Println(name)

		// cmpa holds a list of inputs required per destination
		// i.e. if destination X requires 15 ul of h2o this will be listed separately
		// at this point all of the requests must be for volumes,

		// we need a mapping from these to where they belong
		// do we?
		/*
			cmpa:=value.([]map[string]interface{})
			cmp_map:=make(map[string]interface{}, len(cmpa))
			for _,cmp:=range cmpa{
				srcid:=cmp.Srcid
				cmp_map[srcid]=cmp
			}
		*/

		for n, g := range minorlayoutgroups {
			grp := []string(g)
			// get the group assignment string

			assignment := ass[n]

			// the assignment has the format plateID:row:column:incrow:inccol
			// where inc defines how the next one is to be calculated
			// e.g. {GUID}:A:1:1:0
			// 	{GUID}:A:1:0:1

			asstx := strings.Split(assignment, ":")

			plate := asstx[0]
			toplatenum := wutil.ParseInt(plate)
			row := wutil.AlphaToNum(asstx[1])
			col := wutil.ParseInt(asstx[2])
			incrow := wutil.ParseInt(asstx[3])
			inccol := wutil.ParseInt(asstx[4])

			whats := make([]string, len(grp))
			pltfrom := make([]string, len(grp))
			pltto := make([]string, len(grp))
			plttypefrom := make([]string, len(grp))
			plttypeto := make([]string, len(grp))
			wellfrom := make([]string, len(grp))
			wellto := make([]string, len(grp))
			vols := make([]*wunit.Volume, len(grp))
			fvols := make([]*wunit.Volume, len(grp))
			tvols := make([]*wunit.Volume, len(grp))
			for i, solID := range grp {
				sol := output_solutions[solID]

				// we need to get the relevant component out
				smpl := get_aggregate_component(sol, name)

				// we need to know where this component was assigned to
				inassignmentar := []string(inass[name])
				inassignment, ok := get_assignment(inassignmentar, &input_plates, smpl.Vol)

				if !ok {
					wutil.Error(errors.New(fmt.Sprintf("No input assignment for %s with vol %-4.1f", name, smpl.Vol)))
				}

				inasstx := strings.Split(inassignment, ":")

				inplt := inasstx[0]
				inrow := string(inasstx[1])
				incol := wutil.ParseInt(inasstx[2])

				// we can fill the structure now

				whats[i] = name
				pltfrom[i] = plate_lookup[string(inplt)]
				pltto[i] = plate_lookup[output_plate_layout[toplatenum]]
				wellfrom[i] = inrow + strconv.Itoa(incol)
				wellto[i] = wutil.NumToAlpha(row) + strconv.Itoa(col)
				v := wunit.NewVolume(smpl.Vol, smpl.Vunit)
				v2 := wunit.NewVolume(0.0, "ul")
				vols[i] = &v
				// TODO Get the proper volumes here
				fvols[i] = &v2
				tvols[i] = &v2
				row += incrow
				col += inccol
			}

			ins := liquidhandling.NewTransferInstruction(whats, pltfrom, pltto, wellfrom, wellto, plttypefrom, plttypeto, vols, fvols, tvols /*, parameters.Cnfvol*/)
			instructions.Add(ins)
		}
	}

	inx := instructions.Generate(request.Policies, parameters)
	instrx := make([]liquidhandling.TerminalRobotInstruction, len(inx))
	for i := 0; i < len(inx); i++ {
		instrx[i] = inx[i].(liquidhandling.TerminalRobotInstruction)
	}
	request.Instructions = instrx

	return request
}
Пример #6
0
func solution_setup(request *LHRequest, prms *liquidhandling.LHProperties) (map[string]*wtype.LHSolution, map[string]float64) {
	solutions := request.Output_solutions

	// index of components used to make up to a total volume, along with the required total
	mtvols := make(map[string][]float64, 10)
	// index of components with concentration targets, along with the target concentrations
	mconcs := make(map[string][]float64, 10)
	// keep a list of components which have fixed stock concentrations
	fixconcs := make([]*wtype.LHComponent, 0)
	// maximum solubilities of each component
	Smax := make(map[string]float64, 10)
	// maximum total volume of any solution containing each component
	hshTVol := make(map[string]float64)

	// find the minimum and maximum required concentrations
	// across all the solutions
	for _, solution := range solutions {
		components := solution.Components

		// we need to identify the concentration components
		// and the total volume components, if we have
		// concentrations but no tvols we have to return
		// an error

		arrCncs := make([]*wtype.LHComponent, 0, len(components))
		arrTvol := make([]*wtype.LHComponent, 0, len(components))
		cmpvol := 0.0
		totalvol := 0.0

		for _, component := range components {
			// what sort of component is it?
			conc := component.Conc
			tvol := component.Tvol

			if conc != 0.0 {
				arrCncs = append(arrCncs, component)
			} else if tvol != 0.0 {
				tv := component.Tvol
				if totalvol == 0.0 || totalvol == tv {
					totalvol = tv
				} else {
					// error
					wutil.Error(errors.New(fmt.Sprintf("Inconsistent total volumes %-6.4f and %-6.4f at component %s", totalvol, tv, component.Name)))
				}
			} else {
				cmpvol += component.Vol
			}
		}

		// add everything to the maps

		for _, cmp := range arrCncs {
			nm := cmp.CName
			cnc := cmp.Conc

			_, ok := Smax[nm]

			if !ok {
				Smax[nm] = cmp.Smax
			}

			if cmp.StockConcentration != 0.0 {
				fixconcs = append(fixconcs, cmp)
				continue
			}

			var cncslc []float64

			cncslc, ok = mconcs[nm]

			if !ok {
				cncslc = make([]float64, 0, 10)
			}

			cncslc = append(cncslc, cnc)

			mconcs[nm] = cncslc
			_, ok = hshTVol[nm]
			if !ok || hshTVol[nm] > totalvol {
				hshTVol[nm] = totalvol
			}
		}

		// now the total volumes

		for _, cmp := range arrTvol {
			nm := cmp.CName
			tvol := cmp.Tvol

			var tvslc []float64

			tvslc, ok := mtvols[nm]

			if !ok {
				tvslc = make([]float64, 0, 10)
			}

			tvslc = append(tvslc, tvol)

			mtvols[nm] = tvslc
		}

	} // end solutions
	// so now we should be able to make stock concentrations
	// first we need the min and max for each

	minrequired := make(map[string]float64, len(mconcs))
	maxrequired := make(map[string]float64, len(mconcs))

	//TODO this needs to be migrated elsewhere
	var vmin wunit.Volume = wunit.NewVolume(1.0, "ul")
	if prms.CurrConf != nil {
		vmin = *(prms.CurrConf.Minvol)
	}

	for cmp, arr := range mconcs {
		min := wutil.FMin(arr)
		max := wutil.FMax(arr)
		minrequired[cmp] = min
		maxrequired[cmp] = max
		// if smax undefined we need to deal  - we assume infinite solubility!!

		_, ok := Smax[cmp]

		if !ok {
			Smax[cmp] = 9999999
			wutil.Warn(fmt.Sprintf("Max solubility undefined for component %s -- assuming infinite solubility!", cmp))
		}

	}

	stockconcs := choose_stock_concentrations(minrequired, maxrequired, Smax, vmin.RawValue(), hshTVol)

	// handle any errors here

	// add the fixed concentrations into stockconcs

	for _, cmp := range fixconcs {
		stockconcs[cmp.CName] = cmp.StockConcentration
	}

	// nearly there now! Need to turn all the components into volumes, then we're done

	// make an array for the new solutions

	newSolutions := make(map[string]*wtype.LHSolution, len(solutions))

	for _, solution := range solutions {
		components := solution.Components
		arrCncs := make([]*wtype.LHComponent, 0, len(components))
		arrTvol := make([]*wtype.LHComponent, 0, len(components))
		arrSvol := make([]*wtype.LHComponent, 0, len(components))
		cmpvol := 0.0
		totalvol := 0.0
		totalvolunit := ""

		for _, component := range components {
			// what sort of component is it?
			// what is the total volume ?
			if component.Conc != 0.0 {
				arrCncs = append(arrCncs, component)
			} else if component.Tvol != 0.0 {
				arrTvol = append(arrTvol, component)
				tv := component.Tvol
				totalvolunit = component.Vunit
				if totalvol == 0.0 || totalvol == tv {
					totalvol = tv
				} else {
					// error
					wutil.Error(errors.New(fmt.Sprintf("Inconsistent total volumes %-6.4f and %-6.4f at component %s", totalvol, tv, component.Name)))
				}
			} else {
				// need to add in the volume taken up by any volume components
				cmpvol += component.Vol
				arrSvol = append(arrSvol, component)
			}
		}

		// first we add the volumes to the concentration components

		arrFinalComponents := make([]*wtype.LHComponent, 0, len(components))

		for _, component := range arrCncs {
			name := component.CName
			cnc := component.Conc
			vol := totalvol * cnc / stockconcs[name]
			cmpvol += vol
			component.Vol = vol
			component.Vunit = totalvolunit
			component.StockConcentration = stockconcs[name]
			arrFinalComponents = append(arrFinalComponents, component)
		}

		// next we get the final volume for total volume components

		for _, component := range arrTvol {
			vol := totalvol - cmpvol
			component.Vol = vol
			arrFinalComponents = append(arrFinalComponents, component)
		}

		// then we add the rest

		arrFinalComponents = append(arrFinalComponents, arrSvol...)

		// finally we replace the components in this solution

		solution.Components = arrFinalComponents

		// and put the new solution in the array

		newSolutions[solution.ID] = solution
	}

	return newSolutions, stockconcs
}