def construct_textbook_ensemble(): # create two identical models and make an ensemble model1 = create_test_model("textbook") model1.remove_reactions(model1.reactions[1:3]) model1.id = 'first_textbook' model2 = create_test_model("textbook") model2.remove_reactions(model2.reactions[4:6]) model2.id = 'second_textbook' textbook_ensemble = Ensemble(list_of_models=[model1, model2], identifier='textbook_ensemble') return textbook_ensemble
def construct_textbook_ensemble(): # create two identical models and make an ensemble model1 = create_test_model("textbook") model1.remove_reactions(model1.reactions[1:3]) model1.id = 'first_textbook' model2 = create_test_model("textbook") model2.remove_reactions(model2.reactions[4:6]) model2.id = 'second_textbook' model3 = create_test_model("textbook") model3.remove_reactions(model3.reactions[2:5]) model3.id = 'third_textbook' textbook_ensemble = Ensemble(model_list=[model1,model2,model3], base_id='textbook_ensemble') return textbook_ensemble
def construct_mixed_ensemble(): # create 4 models, which have reactions removed and a bound difference. model1 = create_test_model("textbook") model1.remove_reactions(model1.reactions[1:3]) model1.id = 'first_textbook' model2 = create_test_model("textbook") model2.remove_reactions(model2.reactions[4:6]) model2.id = 'second_textbook' model3 = create_test_model("textbook") model3.remove_reactions(model3.reactions[5:7]) model3.id = 'third_textbook' model4 = model3.copy() model4.id = 'dual_features' model4.reactions[1].lower_bound = 0 model_list = [model1, model2, model3, model4] mixed_ensemble = Ensemble(list_of_models=model_list, identifier='textbook_ensemble') return (mixed_ensemble)
def _build_ensemble_from_gapfill_solutions(model, solutions, universal=None): ensemble = Ensemble(identifier=model.id, name=model.name) ensemble.base_model = model.copy() # generate member identifiers for each solution # Convert the solution to a dictlist so we can retrieve reactions by id solution_dict = {} i = 0 for solution in solutions: solution_id = model.id + '_gapfilled_' + str(i) solution_as_rxn_objs = [ universal.reactions.get_by_id(rxn).copy() for rxn in solution ] solution_dict[solution_id] = DictList() + solution_as_rxn_objs i += 1 # scan through other members and remove them if they are identical. # as long as we're looping, we'll also find reactions that are in # all solutions and get the list of reactions that are in any ensemble. # first, convert the solution dictionary to the same structure except with # reaction ids rather than reaction objects so that we can perform set # operations solutions_as_ids = {} for member_id in solution_dict.keys(): solutions_as_ids[member_id] = [ rxn.id for rxn in solution_dict[member_id] ] used_members = [] duplicate_solutions = [] all_reactions = set() in_all = set() for member_id in solutions_as_ids.keys(): used_members.append(member_id) member_solution = set(solutions_as_ids[member_id]) if in_all: in_all = member_solution & in_all #if this is the first ensemble member, set intersection will fail # because of the empty set, so we need this exception else: in_all = member_solution all_reactions = all_reactions | member_solution for other_member in solutions_as_ids.keys(): if other_member not in used_members: other_solution = solutions_as_ids[other_member] if set(other_solution) == member_solution: duplicate_solutions.append(other_member) used_members.append(other_member) # perform the removal of duplicate solutions on the original solution # object which contains reaction objects rather than reaction ids as # strings for duplicate in duplicate_solutions: solution_dict.pop(duplicate, None) # Reactions that need features are those that were not in all the gapfill # solutions. reactions_needing_features = list(all_reactions - in_all) reactions_needing_features_objs = [ universal.reactions.get_by_id(rxn).copy() for rxn in reactions_needing_features ] # add reaction objects to the base model for all reactions all_reactions_as_objects = [ universal.reactions.get_by_id(rxn).copy() for rxn in all_reactions ] ensemble.base_model.add_reactions(all_reactions_as_objects) # add metabolite objects to the base model for all new metabolites from # the new reactions mets = [x.metabolites for x in all_reactions_as_objects] all_keys = set().union(*(d.keys() for d in mets)) ensemble.base_model.add_metabolites(all_keys) print('building features...') # generate features for the reactions that vary across solutions and add # them to the ensemble. assume that all reactions have the same attribute # values; if different attribute values are desired for reactions with the # same ID, these need to be added to the universal reaction bag prior to # gapfilling features = DictList() for reaction in reactions_needing_features_objs: for attribute in REACTION_ATTRIBUTES: identifier = reaction.id + "_" + attribute name = reaction.name feature = Feature(identifier, name) feature.ensemble = ensemble feature.base_component = (ensemble.base_model.reactions.get_by_id( reaction.id)) feature.component_attribute = attribute # get the states for this feature as {member.id:value} states = {} for member_id in solution_dict.keys(): # get the reaction and it's value for the attribute if reaction.id in [rxn.id for rxn in solution_dict[member_id]]: rxn_obj = solution_dict[member_id].get_by_id(reaction.id) states[member_id] = getattr(rxn_obj, attribute) else: states[member_id] = MISSING_ATTRIBUTE_DEFAULT[attribute] feature.states = states features += [feature] ensemble.features = features print('updating members...') # update members for the ensemble members = DictList() for member_id in solution_dict.keys(): model_states = dict() for feature in ensemble.features: model_states[feature] = feature.get_model_state(member_id) member = Member(ensemble=ensemble,\ identifier=member_id,\ name=ensemble.name,\ states=model_states) members += [member] ensemble.members = members return ensemble