Beispiel #1
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
}
Beispiel #2
0
func choose_plate_assignments(component_volumes map[string]wunit.Volume, plate_types []*wtype.LHPlate, weight_constraint map[string]float64) map[string]map[*wtype.LHPlate]int {

	//
	//	optimization is set up as follows:
	//
	//		let:
	//			Xk 	= 	Number of wells of type Y containing component Z (k = 1...YZ)
	//			Vy	= 	Working volume of well Y
	//			RVy	= 	Residual volume of well Y
	//			TVz	= 	Total volume of component Z required
	//			WRy	=	Rate of wells of type y in their plate
	//			PMax	=	Maximum number of plates
	//			WMax	= 	Maximum number of wells
	//
	//	Minimise:
	//			sum of Xk Wrv RVy
	//
	//	Subject to:
	//			sum of Xk Vy 	>= TVz	for each component Z
	//			sum of WRy Xk 	<= PMax
	//			sum of Xk	<= WMax
	//

	// setup

	lp := glpk.New()
	defer lp.Delete()

	lp.SetProbName("Assignments")
	lp.SetObjName("Z")

	// CHECK THIS

	lp.SetObjDir(glpk.MAX)

	// constraints:
	// 		total component volume
	//		number of plates
	//		number of wells
	n_rows := len(component_volumes) + 2

	lp.AddRows(n_rows)

	cur := 1

	component_order := make([]string, len(component_volumes))

	// volume constraints
	for cmp, vol := range component_volumes {
		component_order[cur-1] = cmp
		lp.SetRowBnds(cur, glpk.LO, vol.ConvertTo(wunit.ParsePrefixedUnit("ul")), 99999.0)
		cur += 1
	}

	// from now on we always have to use component_order

	// plate number constraints

	max_n_plates := weight_constraint["MAX_N_PLATES"] - 1.0
	lp.SetRowBnds(cur, glpk.UP, -99999.0, max_n_plates)
	cur += 1

	// well number constraints
	max_n_wells := weight_constraint["MAX_N_WELLS"]
	lp.SetRowBnds(cur, glpk.UP, -99999.0, max_n_wells)
	cur += 1

	// set up the matrix columns

	num_cols := len(component_order) * len(plate_types)
	lp.AddCols(num_cols)
	cur = 1

	for _, component := range component_order {
		for _, plate := range plate_types {
			// set up objective coefficient, column name and lower bound
			rv := plate.Welltype.ResidualVolume()
			coef := rv.ConvertTo(wunit.ParsePrefixedUnit("ul")) * weight_constraint["RESIDUAL_VOLUME_WEIGHT"]
			lp.SetObjCoef(cur, coef)
			lp.SetColName(cur, component+"_"+plate.PlateName)
			lp.SetColBnds(cur, glpk.LO, 0.0, 0.0)
			lp.SetColKind(cur, glpk.IV)
			cur += 1
		}
	}

	// now set up the constraint coefficients
	cur = 1

	ind := wutil.Series(0, num_cols)

	for c, _ := range component_order {
		row := make([]float64, num_cols+1)
		col := 0
		for i := 0; i < len(component_order); i++ {
			for j := 0; j < len(plate_types); j++ {
				vc := 0.0
				// pick out a set of columns according to which row we're on
				// volume constraints are the working volumes of the wells
				if c == i {
					vol := wunit.NewVolume(plate_types[j].Welltype.Vol, plate_types[j].Welltype.Vunit)
					rvol := wunit.NewVolume(plate_types[j].Welltype.Rvol, plate_types[j].Welltype.Vunit)
					vol.Subtract(&rvol)
					vc = vol.ConvertTo(wunit.ParsePrefixedUnit("ul"))
				}
				row[col+1] = vc
				col += 1
			}
		}
		lp.SetMatRow(cur, ind, row)
		cur += 1
	}

	// now the plate constraint

	row := make([]float64, num_cols+1)
	col := 1
	for i := 0; i < len(component_order); i++ {
		for j := 0; j < len(plate_types); j++ {
			// the coefficient here is 1/the number of this well type per plate
			r := 1.0 / float64(plate_types[j].Nwells)
			row[col] = r
			col += 1
		}
	}

	lp.SetMatRow(cur, ind, row)
	cur += 1

	// finally the well constraint

	row = make([]float64, num_cols+1)
	col = 1
	for i := 0; i < len(component_order); i++ {
		for j := 0; j < len(plate_types); j++ {
			// the number of wells is constrained so we just count
			row[col] = 1.0
			col += 1
		}
	}

	lp.SetMatRow(cur, ind, row)

	iocp := glpk.NewIocp()
	iocp.SetPresolve(true)
	iocp.SetMsgLev(0)
	lp.Intopt(iocp)

	// check constraints

	/*
		for i := 1; i <= n_rows; i++ {
			fmt.Println("ROW : ", i, " VAL : ", lp.MipRowVal(i))
		}
	*/
	// fill assignments - this is the number of wells in the plate of each type needed

	assignments := make(map[string]map[*wtype.LHPlate]int, len(component_volumes))

	cur = 1

	for i := 0; i < len(component_order); i++ {
		cmap := make(map[*wtype.LHPlate]int)
		for j := 0; j < len(plate_types); j++ {
			nwells := lp.MipColVal(cur)

			if nwells > 0 {
				//fmt.Println(component_order[i], " : ", plate_types[j].Type, " N WELLS: ", nwells)
				cmap[plate_types[j]] = int(nwells)
			}
			cur += 1
		}
		assignments[component_order[i]] = cmap
	}

	return assignments
}
Beispiel #3
0
func (lhc *LHComponent) Add(v wunit.Volume) {
	meas := wunit.ConcreteMeasurement{lhc.Vol, wunit.ParsePrefixedUnit(lhc.Vunit)}
	meas.Add(&v)
	lhc.Vol = meas.RawValue()
}