def make_eval_b_candidate_kwargs(data, model, plate_lvl): """Make evalaluation kwargs for multiprocessing b_candidate evaluation. Corresponds to the function genetic.eval_b_candidate. data : A dictionary model : A pickleable CANS Model instance. plate_lvl : An array of plate level parameters. The returned dictionary should be supplied in the call to evolve when using the eval_b_candidate evaluator for multiprocessing. Due to the overhead of loading SBML models, a large number of cores (>20) may be needed before any performance benefit is seen. """ plate = Plate(**_get_plate_kwargs(data)) plate.data_shape = np.array( [len(plate.times), plate.no_cultures * model.no_species]) plate.rr = PickleableRoadRunner() eval_kwargs = { "plate": plate, "fitter": Fitter(model), "sbml": create_sbml(plate, model, data["sim_params"]), "plate_lvl": plate_lvl, } return eval_kwargs
def make_eval_b_candidates_kwargs(data, model, plate_lvl): """Make evalaluation kwargs for in serial b_candidate evaluation. Corresponds to the function genetic.eval_b_candidates. The returned values in the dict eval_kwargs need not be pickleable. data : A dictionary model : A CANS Model instance. plate_lvl : An array of plate level parameters. The returned dictionary should be supplied in the call to evolve when using the eval_b_candidates evaluator for serial processing. """ plate = Plate(**_get_plate_kwargs(data)) no_params = len(plate_lvl) + plate.no_cultures plate.set_rr_model(model, np.ones(no_params)) # Dummy params eval_kwargs = { "plate": plate, "fitter": Fitter(model), "plate_lvl": plate_lvl, } return eval_kwargs
def get_plate_zone(plate, coords, rows, cols): """Return a plate from a zone of a larger plate. Coords are a tuple for the top left culture of a rectangular zone. rows and cols are the size of the new zone. """ no_cultures = plate.no_cultures c_collected = [plate.c_meas[i::no_cultures] for i in range(no_cultures)] c_collected = np.array(c_collected) c_collected.shape = (plate.rows, plate.cols, len(plate.times)) zone = _get_zone(c_collected, coords, rows, cols) c_meas = [zone[:, :, i] for i in range(len(plate.times))] c_meas = np.array(c_meas).flatten() assert len(c_meas) == rows * cols * len(plate.times) zone_indices = list(_get_zone_indices(plate, coords, rows, cols)) zone_data = { "c_meas": c_meas, "times": plate.times, "empties": np.array([ z_i for z_i, p_i in enumerate(zone_indices) if p_i in plate.empties ]), # "genes": np.array(plate.genes)[zone_indices], } zone_plate = Plate(rows, cols, data=zone_data) return zone_plate
def guess_kn(self, start, stop, num, params): """Guess kn from final cell measurement variance. params should have a dummy value, e.g. nan, in place of kn. Returns this array with the guess of kn inserted. """ C_f_var_true = np.var(self.plate.c_meas[-self.plate.no_cultures:]) kns = np.linspace(start, stop, num) kn_index = self.model.params.index("kn") # Make a new Plate so that we do not alter the original # containing true data. sim_plate = Plate(self.plate.rows, self.plate.cols) sim_plate.times = self.plate.times C_f_vars = [] for kn in kns: params[kn_index] = kn sim_plate.sim_params = params sim_plate.set_sim_data(self.model) C_fs = sim_plate.c_meas[-sim_plate.no_cultures:] C_f_vars.append(np.var(C_fs)) # Fit a line by least squares. A = np.vstack([kns, np.ones(len(kns))]).T m, c = np.linalg.lstsq(A, C_f_vars)[0] kn_guess = (C_f_var_true - c) / float(m) params[kn_index] = kn_guess return params.clip(min=0.0)
def resim_zone(plate, model, coords, rows, cols, noise=True): """Resimulate a zone from the underlying parameters.""" zone = Plate(rows, cols) zone.times = plate.times b_index = len(plate.sim_params) - plate.no_cultures plate_lvl = plate.sim_params[:b_index] bs = plate.sim_params[b_index:] zone_bs = get_zone_bs(bs, plate.rows, plate.cols, coords, rows, cols) zone_params = np.append(plate_lvl, zone_bs) zone.sim_params = zone_params zone.set_sim_data(model, noise=noise) return zone
def sim_zone(plate_file, model, coords, rows, cols): """Resimulate and return a zone of a saved plate.""" params = get_zone_params(plate_file, coords, rows, cols) with open(plate_file, 'b') as f: plate_data = json.load(f) times = plate_data['times'] try: assert model.name == plate_data['model'] except AssertionError: print("Plate model is not the same as zone model.") zone = Plate(rows, cols) zone.sim_params = params zone.times = times zone.set_sim_data(model) return zone
def make_eval_plate_lvl_im_neigh_grad_kwargs(data, model, b_bound): """Make eval kwargs for plate level parallel parameter candidate evaluaton. Corresponds to the function genetic.eval_plate_lvl_im_neigh_grad. data : dictionary model : A Pickleable CANS model. b_bound : bound for gradient fitting of b parameters. e.g. [0.0, 100.0]. """ pickleable(model) # Model must be pickleable for multiprocessing. plate = Plate(**_get_plate_kwargs(data)) eval_kwargs = { "plate": plate, "model": model, # Not including amounts. Last two are place holders for # b_guess*1.5 and b_guess. "imag_neigh_params": np.array([1.0, 1.0, 0.0, 0.0, 0.0]), "b_bounds": np.array([b_bound for c in range(plate.no_cultures)]), } return eval_kwargs
return writeSBMLToString(document) if __name__ == "__main__": import numpy as np from cans.plate import Plate from cans.model import CompModelBC, CompModel from cans.plotter import Plotter # Simulate a plate with data and parameters. rows = 3 cols = 3 plate1 = Plate(rows, cols) plate1.times = np.linspace(0, 5, 11) comp_model_bc = CompModelBC() params = { "C_0": 1e-6, "N_0": 0.1, "kn": 1.5 } plate1.set_sim_data(comp_model_bc, b_mean=40.0, b_var=15.0, custom_params=params) # Convert comp model to SBML. sbml = create_sbml(plate1, comp_model_bc, plate1.sim_params, outfile="sbml_models/simulated_{0}x{1}_test_plate_bc.xml".format(rows, cols)) comp_model_ir = CompModel(rev_diff=False)
def plot_zone_est(self, plates, plate_names, est_params, models, coords, rows, cols, title="Zone Estimates", legend=False, filename=None, plot_types=None, vis_ticks=True, log_plate=None, log_params=None): """Plot estimates for a zone. Plotting a zone from a full plate estimate requires simulating for the full plate and then taking the amounts from the zone rather than just simulating from the zone params. plates : list of Plates with different c_meas data. If both estimates are from the same Plate you need only provide one Plate in the list. plate_neams : list of strings. Names of plates to use in figure legend. est_params : list of parameter estimate from fits of different models. models : list of models corresponding to est_params. coords : tuple of coordinates of top left culture in zone (indices start from zero). row, cols : rows and columns for zone. plot_types : list of strings for plot labels. If the first plate is to plot the estimate and the second a simulation use e.g. ["Est", "Sim"] log_plate : A plate from a QFA R logistic fit. """ smooth_times = np.linspace(plates[0].times[0], plates[0].times[-1], 100) if log_plate is not None: log_zone = get_qfa_R_zone(log_plate, log_params, coords, rows, cols, smooth_times) smooth_plate = Plate(plates[0].rows, plates[0].cols) smooth_plate.times = smooth_times smooth_plate.smooth_amounts = [] for params, model in zip(est_params, models): smooth_plate.set_rr_model(model, params) smooth_amounts = smooth_plate.rr_solve() # print("1") # print(smooth_amounts) # smooth_amounts = np.split(smooth_amounts, self.model.no_species, # axis=1) smooth_plate.smooth_amounts.append(smooth_amounts) plates[0].amounts = [] # Simulate comp model at observed timepoints and get the amounts for the zone plates[0].set_rr_model(models[0], est_params[0]) plates[0].amounts = plates[0].rr_solve() zone_amounts = get_zone_amounts(plates[0].amounts, plates[0], models[0], coords, rows, cols) zones = [] for plate in plates: zone = get_plate_zone(plate, coords, rows, cols) zone.times = plate.times zones.append(zone) # Caclulate objective function for comp model comp_obj_funs = [] for i, culture in enumerate(zone.cultures): comp_obj_funs.append(least_sq(culture.c_meas, zone_amounts[:, i])) print(np.sum(comp_obj_funs)) zone_smooth_amounts = [] for model, smooth_amounts in zip(models, smooth_plate.smooth_amounts): sim_amounts = get_zone_amounts(smooth_amounts, plate, model, coords, rows, cols) sim_amounts = np.split(sim_amounts, self.model.no_species, axis=1) zone_smooth_amounts.append(sim_amounts) fig, grid = self._make_grid(zone, np.array(zone_smooth_amounts).flatten(), False, title, vis_ticks) if plot_types is None: plot_types = ["Est." for plate in plates] species_labels = { "C": "Cells", "N": "Nutrients", } # Check if c_meas are equal for the plates so don't plot # twice. Currently only checks for two. if len(plates) == 2 and len(plates[0].c_meas) == len(plates[1].c_meas): same_c_meas = np.array_equal(plates[0].c_meas, plates[1].c_meas) else: same_c_meas = False colors = { "C": ["b", "b", "b"], "N": ["y", "y", "g"], } lines = ["-", "--", "--"] # for i, ax in enumerate(grid): # # Plot c_meas. # for plate_name, c, zone in zip(plate_names, self.c_meas_colors, zones): # # for plate_name, c, zone in zip(plate_names, colors["C"][:-1], zones): # if same_c_meas: # ax.plot(zone.times, zone.c_meas[i::zone.no_cultures], # 'x', color=c, label='Observed Cells', # ms=self.ms, mew=self.mew) # break # else: # ax.plot(zone.times, zone.c_meas[i::zone.no_cultures], # 'x', color=c, # label='Observed Cells {0}'.format(plate_name), # ms=self.ms, mew=self.mew) # # continue # Remove this line # # Plot smooth amounts for each estimate. # plot_zip = zip(plate_names, plot_types, zone_smooth_amounts, models) # for k, (plate_name, plot_type, smooth_amounts, model) in enumerate(plot_zip): # for j, (amounts, species) in enumerate(zip(smooth_amounts, model.species)): # # if j==1: break # ax.plot(smooth_times, amounts[:, i], colors[species][k], # label="{0} ".format(plot_type) + species_labels[species] + " {0}".format(plate_name), # # lw=self.lw, ls=self.linestyles[plate_names.index(plate_name)]) # lw=self.lw, ls=lines[k]) # if log_zone is not None: # # for ax, culture in zip(grid, log_zone.cultures): # # ax.plot(smooth_times, culture.c_smooth, '-', # # label='Logistic Cells', color="r", lw=self.lw) # for ax, culture in zip(grid, log_zone.cultures): # ax.plot(smooth_times, culture.c_smooth, '-', # label="Log. obj. {0:.3f}".format(culture.least_sq*1000), # color="r", lw=self.lw) # ax.legend(loc='best', fontsize=self.legend_font_size) # Add text to plots with objective fuction values # Alternative labels objective function. for i, ax in enumerate(grid): # Plot c_meas. for plate_name, c, zone in zip(plate_names, self.c_meas_colors, zones): # for plate_name, c, zone in zip(plate_names, colors["C"][:-1], zones): if same_c_meas: ax.plot(zone.times, zone.c_meas[i::zone.no_cultures], 'x', color=c, ms=self.ms, mew=self.mew) break else: ax.plot(zone.times, zone.c_meas[i::zone.no_cultures], 'x', color=c, ms=self.ms, mew=self.mew) # continue # Remove this line # Plot smooth amounts for each estimate. plot_zip = zip(plate_names, plot_types, zone_smooth_amounts, models) for k, (plate_name, plot_type, smooth_amounts, model) in enumerate(plot_zip): for j, (amounts, species) in enumerate( zip(smooth_amounts, model.species)): if j == 0 and k == 0: ax.plot( smooth_times, amounts[:, i], colors[species][k], label="Obj. {0:.2f}".format(comp_obj_funs[i] * 10000), # lw=self.lw, ls=self.linestyles[plate_names.index(plate_name)]) lw=self.lw, ls=lines[k]) else: ax.plot( smooth_times, amounts[:, i], colors[species][k], # lw=self.lw, ls=self.linestyles[plate_names.index(plate_name)]) lw=self.lw, ls=lines[k]) if log_zone is not None: for ax, culture in zip(grid, log_zone.cultures): ax.plot(smooth_times, culture.c_smooth, '-', label="Obj. {0:.2f}".format(culture.least_sq * 10000), color="r", lw=self.lw) ax.legend(loc=2, fontsize=self.legend_font_size) self._hide_last_ticks(grid, zone.rows, zone.cols) # plt.tight_layout() # # Change order of labels. # ax = grid[-1] # handles, labels = ax.get_legend_handles_labels() # new_order = [0, 2, 3, 1, 4, 5, 6, 7] # handles2 = [handles[i] for i in new_order] # labels2 = [labels[i] for i in new_order] # # Change order of labels. # ax = grid[-1] # handles, labels = ax.get_legend_handles_labels() # new_order = [0, 2, 1, 3, 4] # handles2 = [handles[i] for i in new_order] # labels2 = [labels[i] for i in new_order] # For multiple columns reorder the axis labels by row def flip(items, ncol): """http://stackoverflow.com/a/10101532""" return itertools.chain(*[items[i::ncol] for i in range(ncol)]) ax = grid[-1] handles, labels = ax.get_legend_handles_labels() handles = flip(handles, self.legend_cols) labels = flip(labels, self.legend_cols) if legend: # grid[1].legend(handles2, labels2, loc='best', fontsize=self.legend_font_size) grid[-1].legend(handles, labels, loc='best', fontsize=self.legend_font_size, ncol=self.legend_cols, bbox_to_anchor=self.bbox) if filename is None: plt.show() else: plt.savefig(filename) plt.close()
def plot_est_rr(self, plate, est_params, title='Estimated Growth', sim=False, filename=None, legend=False, vis_ticks=True): # Smooth times for sims. sim_times = np.linspace(plate.times[0], plate.times[-1], 100) # Cannot deepcopy swig objects belonging to plate so define # new plate and simulate smooth curves from the estimates. est_plate = Plate(plate.rows, plate.cols) est_plate.times = sim_times est_plate.set_rr_model(self.model, est_params) est_amounts = self.model.rr_solve(est_plate, est_params) est_amounts = np.split(est_amounts, self.model.no_species, axis=1) if sim: # "True" data sim_amounts = np.split(plate.sim_amounts, self.model.no_species, axis=1) fig, grid = self._make_grid(plate, est_amounts, sim, title, vis_ticks) for i, ax in enumerate(grid): if not sim: # and i not in plate.empties: # Plot c_meas. ax.plot(plate.times, plate.c_meas[i::plate.no_cultures], 'x', color="black", label='Observed Cells', ms=self.ms, mew=self.mew) for j, species in enumerate(self.model.species): ax.plot(sim_times, est_amounts[j][:, i], self.colours[j], label="Est " + self.species[species], lw=self.lw) if j == 0: # and i in plate.empties: # Do not plot c_meas for empty cultures. continue elif sim: # Plot all "true" amounts (e.g. including C and # unobservable, but known, N.) ax.plot(plate.times, sim_amounts[j][:, i], 'x' + self.colours[j], label="True" + self.species[species], ms=self.ms, mew=self.mew) else: continue self._hide_last_ticks(grid, plate.rows, plate.cols) if legend: grid[-1].legend(loc='best', fontsize=self.legend_font_size) if filename is None: plt.show() else: plt.savefig(filename) plt.close()
def remove_edges(array, rows, cols): """Remove values at edge indices from a flat array.""" empty_plate = Plate(rows, cols) return np.array(array)[list(empty_plate.internals)]
if __name__ == "__main__": from cans.plate import Plate from cans.model import CompModel from cans.plotter import Plotter outdir = "sbml_models/sim_3x3/" c_meas_path = outdir + "c_meas.csv" sbml_path = outdir + "sim_3x3.xml" rows = 3 cols = 3 comp_model = CompModel() comp_plotter = Plotter(comp_model) plate1 = Plate(rows, cols) plate1.times = np.linspace(0, 5, 11) true_params = {'N_0': 0.1, 'kn': 0.5} true_params['C_0'] = true_params['N_0'] / 100000.0 plate1.set_sim_data(comp_model, b_mean=100.0, b_var=50.0, custom_params=true_params) # comp_plotter.plot_est(plate1, plate1.sim_params, sim=True) plate1.set_rr_model(comp_model, plate1.sim_params, outfile=sbml_path) print(plate1.rr.model.getFloatingSpeciesInitConcentrations()) write_c_meas(plate1, c_meas_path)