class TestPathway(unittest.TestCase): def setUp(self): self.logger = create_logger(name='Test core.Pathway') self.pathway_fixture = { 'flux': [ -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 2.0, 1.0, 1.0, 1.0, -1.0, 1.0 ], 'iteration': 1, 'reaction_id': [ 'R00200', 'R00300', 'R00658', 'R01059', 'R01063', 'R01512', 'R01518', 'R01519', 'R01538', 'R08570', 'EX_glc', 'EX_nad', 'EX_adp', 'EX_phosphate', 'EX_pyruvate', 'EX_nadh', 'EX_atp', 'EX_h2o', 'EX_nadp', 'EX_nadph' ] } self.p1 = Pathway(id=1, name='OptStoic', reaction_ids=self.pathway_fixture['reaction_id'], fluxes=self.pathway_fixture['flux']) @unittest.skip("Need to update test!") def test_rearrange_pathway(self): self.logger.info("Test rearranging reaction order") self.p1.rearrange_reaction_order() def test_kegg_model_generation(self): self.logger.info( "Creating 'res' folder in the current directory if not exist...") # outputFilepath = 'res' # outputFilename = 'OptStoic' # try: # os.makedirs(outputFilepath) # except OSError: # if not os.path.isdir(outputFilepath): # raise Exception self.logger.info("Test create KEGG model file") filename = "./test_kegg_model_generation.txt" f = open(filename, 'a+') kegg_model_text = generate_kegg_model(self.p1, filehandle=f) print(kegg_model_text) self.assertIn('R01512', kegg_model_text) self.assertIn('R01512', kegg_model_text) f.close() if os.path.exists(filename): os.remove(filename)
def runAnalysis(resultDict, numATP, outputFilePath, imgFormat='png', shift_pathway_id_by=0,\ sourceSubstrateID='C00031', endSubstrateID='C00022', darkBackgroundMode=False): logging.info("Analyzing results... \n") pathway_objects = [] outputFileName='OptStoic_gams_{0}ATP'.format(numATP) f = open(os.path.join(outputFilePath, outputFileName + '_KeggModel.txt'), 'w+') for ind, res in sorted(resultDict.items()): logging.debug("Pathway %s"%ind) if "pathway" not in res: logging.info("OptStoic terminated with infeasible solution.") continue elif "num_reaction" not in res: logging.info("Pathway is incomplete...") continue p = Pathway(id=int(ind)+shift_pathway_id_by, name='OptStoic_gams', reaction_ids=list(res['pathway'].keys()), fluxes=list(res['pathway'].values()), sourceSubstrateID=sourceSubstrateID, endSubstrateID=endSubstrateID, total_flux_no_exchange=res['total_flux_no_exchange'], note={'modelstat': res.get("modelstat"), 'solvestat': res.get("solvestat")}) p.rearrange_reaction_order() pathway_objects.append(p) generate_kegg_model(p, filehandle=f) graph_title = "{0}_{1}ATP_P{2}".format(p.name, p.nATP, p.id) if res['modelstat'] != 1: graph_title += '; Modelstat={0}'.format(res['modelstat']) if imgFormat: draw_pathway(p, os.path.join(outputFilePath+'/pathway_{0:03d}'.format(p.id)), imageFormat=imgFormat, graphTitle=graph_title, darkBackgroundMode=darkBackgroundMode) #pickle.dump(resultDict, open(outputFilePath+outputFileName+'_pathways_dict.pkl', 'w+')) pickle.dump(pathway_objects, open(outputFilePath + outputFileName + '_pathways_obj.pkl', 'w+')) logging.info("\nDone!\n") logging.info("Check your output folder: %s"%outputFilePath) return pathway_objects
def setUp(self): self.logger = create_logger(name='Test core.Pathway') self.pathway_fixture = { 'flux': [ -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 2.0, 1.0, 1.0, 1.0, -1.0, 1.0 ], 'iteration': 1, 'reaction_id': [ 'R00200', 'R00300', 'R00658', 'R01059', 'R01063', 'R01512', 'R01518', 'R01519', 'R01538', 'R08570', 'EX_glc', 'EX_nad', 'EX_adp', 'EX_phosphate', 'EX_pyruvate', 'EX_nadh', 'EX_atp', 'EX_h2o', 'EX_nadp', 'EX_nadph' ] } self.p1 = Pathway(id=1, name='OptStoic', reaction_ids=self.pathway_fixture['reaction_id'], fluxes=self.pathway_fixture['flux'])
def solve_gurobi_cl(self, exclude_existing_solution=False, outputfile="OptStoic_pulp_result_gcl.txt", max_iteration=None, cleanup=True, gurobi_options=GUROBI_OPTIONS): """ Solve OptStoic problem using Gurobi command line (gurobi_cl) when pulp.solvers.GUROBI_CMD failed. Require the module "gurobi_command_line_solver.py". Args: exclude_existing_solution (bool, optional): If true and if self.pathway is not None, exclude the pathways from being identified. outputfile (str, optional): name of outpufile max_iteration (None, optional): Externally specified maximum number of pathway to be found using OpStoic. If not specified, it will set to the internal max iterations. cleanup (bool, optional): If True, delete the temporary .lp and .sol file. Set as False for debugging. gurobi_options (TYPE, optional): Description Returns: TYPE: Description Raises: ValueError: Description """ if self.objective not in ['MinFlux', 'MinRxn']: raise ValueError("The objective for OptStoic is not correctly " "defined. Please use either 'MinFlux' or " "'MinRxn'.") if max_iteration is None: max_iteration = self.max_iteration t1 = time.time() self.logger.info( "Finding multiple pathways using" " Optstoic %s and Gurobi CL...", self.objective) lp_prob, v, vf, vb, yf, yb, a, G = self.create_minflux_problem() # Create integer cut for existing pathways if exclude_existing_solution and bool(self.pathways): self.iteration = max(self.pathways.keys()) + 1 if self.iteration > max_iteration: raise ValueError('Max iteration is less than current ' 'iteration. Increase max_iteration ' 'before solving!') for ind, pathway in self.pathways.items(): rxnlist = list(set(pathway.reaction_ids_no_exchange)) condition = pulp.lpSum([(1 - yf[j] - yb[j]) for j in rxnlist]) >= 1 lp_prob += condition, "IntegerCut_%d" % ind # Solve problem self.logger.info("Solving problem...") # if self.iteration == 1: # result_output = open(os.path.join( # self.result_filepath, outputfile), "w+") # else: # result_output = open(os.path.join( # self.result_filepath, outputfile), "a+") while True and self.iteration <= max_iteration: self.logger.info("Iteration %s", self.iteration) lp_prob.writeLP(self.lp_prob_fname + ".lp", mip=1) e1 = time.time() lp_status, solver_message = solve_with_gurobi_cl_debug( self.lp_prob_fname, options=gurobi_options) e2 = time.time() self.logger.info("This iteration solved in %.3f seconds.", (e2 - e1)) # The solution is printed if it was deemed "optimal if lp_status in ["Optimal", "Time_limit"]: objective_function, varValue = parse_gurobi_sol( self.lp_prob_fname) res = {} res['reaction_id'] = [] res['flux'] = [] res['iteration'] = self.iteration res['time'] = (e2 - e1) res['modelstat'] = lp_status res['solvestat'] = solver_message # result_output.write("\nIteration no.: %d\n" %self.iteration) # result_output.write("\nModelstat: %s\n" %lp_status) for j in self.database.reactions: if 'v_' + j in varValue: v = varValue['v_' + j] if v > EPS or v < -EPS: res['reaction_id'].append(j) res['flux'].append(v) #result_output.write("%s %.8f\n" %(j, v)) # result_output.write("%s = %.8f\n" %(self.objective, objective_function)) # result_output.write("----------------------------------\n\n") integer_cut_reactions = list( set(res['reaction_id']) - set(self.database.user_defined_export_rxns)) self.pathways[self.iteration] = Pathway( id=self.iteration, name='Pathway_{:03d}'.format(self.iteration), reaction_ids=res['reaction_id'], fluxes=res['flux'], sourceSubstrateID='C00031', endSubstrateID='C00022', note=res) # Keep a copy of pathways in case program terminate midway self.write_pathways_to_json(json_filename="temp_pathways.json") # Integer cut constraint is added so that # the same solution cannot be returned again condition = pulp.lpSum([(1 - yf[j] - yb[j]) for j in integer_cut_reactions]) >= 1 lp_prob += condition, "IntegerCut_%d" % self.iteration self.iteration += 1 # If a new optimal solution cannot be found, end the program else: break # result_output.close() # Clean up directory if cleanup: self.logger.debug("Cleaning up directory...") os.remove("./" + self.lp_prob_fname + ".lp") os.remove("./" + self.lp_prob_fname + ".sol") os.remove("./gurobi.log") self.lp_prob = lp_prob return self.lp_prob, self.pathways
def solve(self, exclude_existing_solution=False, outputfile="OptStoic_pulp_result.txt", max_iteration=None): """ Solve OptStoic problem using pulp.solvers interface Args: exclude_existing_solution (bool, optional): If True, create and add integer cut constraints for pathways that are found using the same OptStoic instance, but solved in previous function call. outputfile (str, optional): name of outpufile max_iteration (None, optional): Externally specified maximum number of pathway to be found using OpStoic. If not specified, it will set to the internal max iterations. Returns: TYPE: Description Raises: ValueError: Description """ if self.objective not in ['MinFlux', 'MinRxn']: raise ValueError( "The objective for OptStoic is not correctly defined. Please use either 'MinFlux' or 'MinRxn'." ) if max_iteration is None: max_iteration = self.max_iteration self.logger.info("Finding multiple pathways using Optstoic %s...", self.objective) lp_prob, v, vf, vb, yf, yb, a, G = self.create_minflux_problem() # Create integer cut for existing pathways if exclude_existing_solution and bool(self.pathways): self.iteration = max(self.pathways.keys()) + 1 if self.iteration > max_iteration: raise ValueError('Max iteration is less than current ' 'iteration. Increase max_iteration ' 'before solving!') for ind, pathway in self.pathways.items(): rxnlist = list(set(pathway.reaction_ids_no_exchange)) condition = pulp.lpSum([(1 - yf[j] - yb[j]) for j in rxnlist]) >= 1 lp_prob += condition, "IntegerCut_%d" % ind self.logger.info("Solving problem...") # if self.iteration == 1: # result_output = open(os.path.join(self.result_filepath, outputfile), "w+") # else: # result_output = open(os.path.join(self.result_filepath, outputfile), "a+") while True and self.iteration <= max_iteration: self.logger.info("Iteration %s", self.iteration) # lp_prob.writeLP("OptStoic.lp", mip=1) # optional e1 = time.time() lp_prob.solve(solver=self.pulp_solver) e2 = time.time() self.logger.info("This iteration solved in %.3f seconds.", (e2 - e1)) # The solution is printed if it was deemed "optimal if pulp.LpStatus[lp_prob.status] == "Optimal": self.logger.info("Writing result to output file...") # result_output.write("\nIteration no.: %d\n" %self.iteration) # result_output.write("\nModelstat: %s\n" %pulp.LpStatus[lp_prob.status]) res = {} res['reaction_id'] = [] res['flux'] = [] res['iteration'] = self.iteration res['time'] = (e2 - e1) res['modelstat'] = "Optimal" for j in self.database.reactions: if v[j].varValue is not None: if v[j].varValue > EPS or v[j].varValue < -EPS: res['reaction_id'].append(j) res['flux'].append(v[j].varValue) # result_output.write("%s %.8f\n" %(v[j].name, v[j].varValue)) # result_output.write("%s = %.8f\n" % (self.objective, pulp.value(lp_prob.objective))) # result_output.write("----------------------------------\n\n") integer_cut_reactions = list( set(res['reaction_id']) - set(self.database.user_defined_export_rxns)) self.pathways[self.iteration] = Pathway( id=self.iteration, name='Pathway_{:03d}'.format(self.iteration), reaction_ids=res['reaction_id'], fluxes=res['flux'], sourceSubstrateID='C00031', endSubstrateID='C00022', note=res) self.write_pathways_to_json(json_filename="temp_pathways.json") # Integer cut constraint is added so that # the same solution cannot be returned again condition = pulp.lpSum([(1 - yf[j] - yb[j]) for j in integer_cut_reactions]) >= 1 lp_prob += condition, "IntegerCut_%d" % self.iteration self.iteration += 1 # If a new optimal solution cannot be found, end the program else: break # result_output.close() self.lp_prob = lp_prob return self.lp_prob, self.pathways
} EMP = { 'R00200': -2.00000000, 'R00299': 1.00000000, 'R00658': 2.00000000, 'R00756': 1.00000000, 'R00771': 1.00000000, 'R01015': -1.00000000, 'R01061': 2.00000000, 'R01068': 1.00000000, 'R01512': -2.00000000, 'R01518': -2.00000000, 'EX_glc': -1.00000000, 'EX_nad': -2.00000000, 'EX_adp': -2.00000000, 'EX_phosphate':-2.00000000, 'EX_pyruvate': 2.00000000, 'EX_nadh': 2.00000000, 'EX_atp': 2.00000000, 'EX_h2o': 2.00000000, 'EX_h+': 2.00000000 } EDpath = Pathway(id='ED', name='ED', reaction_ids=list(ED.keys()), fluxes=list(ED.values())) EDpath.rearrange_reaction_order() res = [] for cpath in all_pathways: if EDpath.is_same_pathway_with(cpath): print(cpath) res.append(EDpath.get_pathway_similarity_index(cpath))