def end(cls, exception=''): """Calls method to perform necessary steps for clean exit.""" Plot.end() if exception: Log.add(str(exception)) Log.add('Exiting program') Log.print() exit()
def end(cls): """Terminates graphics engine cleanly""" curses.nocbreak() cls.scr.keypad(False) curses.echo() curses.endwin() Log.add('Terminated plotter')
def init(cls,locked): cls.uis["static"] = Static_Window(16,0) cls.uis["left"] = Panel(["Info", "Minerals", "Elevation","Humidity"],"left") cls.uis["right"] = Panel(["Build", "Select","Remove"],"right") cls.uis["info"] = Widget([{'label':'Height: ','value':0}, {'label':'Minerals: ','value':0}, {'label':'Humidity: ','value':0}]) cls.locked = locked cls.view = "Elevation" cls.string_repr = "Terrain State - " + cls.view Log.add('State set to terrain')
def init(cls): cls.string_repr = "Main State" cls.uis["static"] = None cls.uis["left"] = Panel(["Ships", "Production","Resources"],"left") cls.uis["right"] = Panel(["Colonies","Research","Pause"],"right") cls.uis["bottom"] = Panel(["Next Turn"],"bottom") cls.uis["top"] = Panel(["Map", "Info","Ship","Battle","Tech"],"top") cls.lock = False middle = [i//2 for i in Board.size] cls.posx,cls.posy = middle[0],middle[1] cls.panx,cls.pany = Board.size[0] - int(Plot.x /2), 18 + int(0.5 * ((Board.size[1] - int(Plot.y *2)))) Log.add('State set to map')
def move(cls,x1,y1,x2,y2): """Move object in terrain[x1][y1] to terrain[x2][y2].""" #TODO: Move logic to logic.py distance = dist(x1,y1,x2,y2) if cls.terrain[x2][y2].search(): Log.add("Ship movement failed, obstacle detected.") pass elif distance <= cls.terrain[x1][y1].fuel: Log.add("Moving ship from (" + str(x1) + ","+str(y1) +") to ("+ str(x2) + ","+str(y2)+")") cls.terrain[x2][y2] = cls.terrain[x1][y1] cls.terrain[x1][y1] = Empty() cls.terrain[x2][y2].deplete(distance)
def handle_input(cls): """Takes the key pressed by the user and calls the appropiate method. Bindings: q -- Quits game / Quits Menu w,a,s,d -- Moves cursor / UI Selection e -- locks and unlocks cursor / Accept t y u g h j b n m """ #change will be False if there is no need to change stage #if there is, change[0] will contain a string indicating either the stage #or an instruction for moving in the stage chain (like "back") #further indexes will contain the necessary arguments for the transition, like the object key = cls.get_input() change = cls.state.handle_input(key) if change: if change[0] == "end": cls.end() elif change[0] == "terrain": cls.state = State_Terrain cls.state_chain.append(cls.state) cls.state.init(change[1]) elif change[0] in ["Minerals", "Humidity", "Elevation", "Info"]: cls.state = State_Terrain cls.state_chain[-1] = cls.state cls.state.change_view(change[0]) elif change[0] in ["Build", "Select", "Remove"]: cls.state.change_action(change[0]) elif change[0] == "back": cls.state_chain = cls.state_chain[:-1] cls.state = cls.state_chain[-1] elif change[0] == "main": cls.state_chain = cls.state_chain[0] cls.state = cls.state_chain[0] Log.add(str(cls.state_chain))
class TestLog(unittest.TestCase): def setUp(self): self.client = Redis(decode_responses=True) self.client.flushdb() self.log = Log(self.client, '25, March') self.log1 = "03:00 server up online" self.log2 = "03:15 handle request 1" self.log3 = "03:16 handle request 2" def test_add_works(self): self.assertTrue(len(self.log.get_all()) == 0) self.log.add(self.log1) self.assertTrue(len(self.log.get_all()) == 1) def test_get_all_works(self): self.assertEqual(self.log.get_all(), []) self.log.add(self.log1) self.log.add(self.log2) self.log.add(self.log3) result = self.log.get_all() self.assertEqual(self.log1, result[0]) self.assertEqual( self.log2, result[1], ) self.assertEqual(self.log3, result[2])
def start(cls): """Initializes graphics engine, and returns an instance of the curses Screen class. Sets starting positions for cursor and camera, initializes color profiles and terminal settigs. """ scr = curses.initscr() curses.noecho() curses.cbreak() curses.start_color() curses.use_default_colors() scr.keypad(True) curses.init_pair(1, curses.COLOR_RED, -1) curses.init_pair(2, curses.COLOR_BLUE, -1) curses.init_pair(3, curses.COLOR_GREEN, -1) curses.init_pair(4, curses.COLOR_WHITE, -1) curses.init_pair(5, curses.COLOR_BLACK, 7) scr.clear() cls.y, cls.x = scr.getmaxyx() cls.y -= 1 Log.add(str(cls.x)) cls.scr = scr Log.add('Plotter initialized')
def start(cls,star_radius): cls.terrain = [[Empty() for i in range(cls.size[1])] for j in range(cls.size[0])] cls.gen_star(star_radius) cls.gen_planets(int(Config.config['Constants']['CantPlanets'])) cls.spawn_tests() Log.add('Board initialized')
class Morph: # These are the allowed properties of a morph object. Values not specified # by user are set to None # This is an Abstract Object representing the Morph of a metabolic model # from one species to a close relative genome. It has information related to # the source model, the target genome, the reactions in the model as it is # morphed from source import to target, and the set of properties = { 'src_model', 'genome', 'probanno', 'protcomp', 'model', 'rxn_labels', 'ws_id', 'ws_name', 'trans_model', 'recon_model', 'media', 'probhash', 'log', 'merge_conflicts', 'service' } def __init__(self, *arg_hash, **kwargs): """ Initiializes a Morph! A Morph needs each of the following set: src_model: (FBAModel) the model of the source organism genome: (Genome) the genome of the target organism probanno: (ReactionProbabilities) the likelihoods for KBase reactions in the target organism protcomp: (ProteomeComparison) the proteome comparison between source and target genomes media: (Media) the media for the source model and subsequent models :param arg_hash: a dictionary with the attributes desired as keys :param kwargs: keyword arguments :return: """ self.src_model = None self.model = None self.genome = None self.probanno = None self.protcomp = None self.model = None self.rxn_labels = None self.media = None self.recon_model = None self.trans_model = None self.probhash = None self.log = None self.ws_id = None self.ws_name = None self.essential_ids = None self.removed_ids = None self.service = None for dictionary in arg_hash: for key in dictionary: if key in Morph.properties: setattr(self, key, dictionary[key]) for key in kwargs: if key in Morph.properties: setattr(self, key, kwargs[key]) for prop in Morph.properties: if not hasattr(self, prop): setattr(self, prop, None) if self.log is None: self.log = Log(self) if self.ws_id is None: raise ValueError() self._check_rep() def _check_rep(self): if self.model is not None: assert isinstance(self.model, FBAModel), str(type(self.model)) if self.src_model is not None: assert isinstance(self.src_model, FBAModel), str(type(self.src_model)) if self.genome is not None: assert isinstance(self.genome, Genome), str(type(self.genome)) if self.media is not None: assert isinstance(self.media, Media), str(type(self.media)) if self.probanno is not None: assert isinstance(self.probanno, ReactionProbabilities), str(type(self.probanno)) if self.protcomp is not None: assert isinstance(self.protcomp, ProteomeComparison), str(type(self.protcomp)) if self.trans_model is not None: assert isinstance(self.trans_model, FBAModel), str(type(self.trans_model)) if self.recon_model is not None: assert isinstance(self.recon_model, FBAModel), str(type(self.recon_model)) def to_json(self, filename=None): data = {} for prop in Morph.properties: val = self.__dict__[prop] if hasattr(self, prop) and val is not None: if isinstance(val, StoredObject): data[prop] = self.__dict__[prop].to_json() elif isinstance(val, Log): data[prop] = val.to_json() else: data[prop] = val if filename is not None: with open(filename, 'w') as f: f.write(json.dumps(data)) else: return json.dumps(data) @staticmethod def from_json(json_str): data = json.loads(json_str) args = {} for key in data: if key in {'src_model', 'model', 'recon_model', 'trans_model'}: args[key] = FBAModel.from_json(data[key]) elif key == 'genome': args[key] = Genome.from_json(data[key]) elif key == 'protcomp': args[key] = ProteomeComparison.from_json(data[key]) elif key == 'probanno': args[key] = ReactionProbabilities.from_json(data[key]) elif key == 'media': args[key] = Media.from_json(data[key]) elif key == 'log': args[key] = Log.from_json(data[key]) else: args[key] = data[key] return Morph(args) @staticmethod def from_json_file(filename): with open(filename, 'r') as f: return Morph.from_json(f.read()) # Overridden Functions to produce unique output def __str__(self): output = '' for key in vars(self): attr = getattr(self, key) if isinstance(attr, dict): attr = attr.keys() if len(attr) < 100: output += str(key) + ': ' + str(attr) + '\n' else: output += str(key) + ': ' + str( attr[0:100]) + ' ... (more)\n' else: output += str(key) + ': ' + str(attr) + '\n' return output def __repr__(self): return str(self) def __unicode__(self): return unicode(str(self)) def fill_src_to_media(self): """ Gap-fills the Morphs source model to the provided media :return: None """ prev = FBAModel(self.src_model.object_id, self.src_model.workspace_id, service=self.service) self.src_model = self.src_model.copy(self.service, workspace_id=self.ws_id) result = self.service.gapfill_model(self.src_model, self.media, workspace=self.ws_id) self.src_model = FBAModel(result[0], result[1], service=self.service) self.log.add('gapfill', prev, self.src_model, context='fill_src_to_media') def runfba(self, model=None, media=None): """ Run FBA on the model in the Morph :param model: (optional) FBAModel, default is morph.model :param media: (optional) Media, default is morph.media :return: FBA """ if model is None: model = self.model if media is None: media = self.media objid, wsid = self.service.runfba(model, media, self.ws_id) return FBA(objid, wsid, service=self.service) def translate_features(self): """ Translate morph.model using ProteomeComparison (morph.procomp) to a translated model :return: None (sets morph.trans_model) """ prev = copy.deepcopy(self.trans_model) result = self.service.translate_model(self.src_model, self.protcomp, workspace=self.ws_id) self.trans_model = FBAModel(result[0], result[1], service=self.service) self.log.add('model_translation', prev, self.trans_model, context='translate_features') def reconstruct_genome(self): """ Reconstruct the genome using automated reconstruction in the service form morph.genome :return: None (sets morph.recon_model) """ prev = copy.deepcopy(self.recon_model) result = self.service.reconstruct_genome(self.genome, workspace=self.ws_id) self.recon_model = FBAModel(result[0], result[1], service=self.service) self.log.add('genome_reconstruction', prev, self.recon_model, context='reconstruct_genome') def label_reactions(self): """ Labels morph's reactions from translated model, reconstruction, and source Populates the rxn_labels attribute in the Morph object with a Dictionary of four dictionaries of reaction_id -> value tuples. The first level dicts are named with the keys: - gene-match - gene-no-match - no-gene - recon Populates morph.probhash with a dictionary of compartment-truncated reaction_ids to their probability relative to genome in question (derived from morph.probanno). Also populates morph.objects, morph.info with data from KBase objects (advanced use) Technical Details (Consult if you are encountering issues): For simplicity, an end user can treat the interiors of each dictionary like a set of reaction ids, but it is important to note the this is actually a nested dictionary with entries of the form: reaction_id -> (model_index, probability) Thus, some set behavior works, but some doesn't, the user must account for the fact that these are dictionaries: >>>'rxn09073_c0' in morph.rxn_labels['gene-no-match'] works and returns True or False, indicating whether or not rxn09073_c0 is a gene-no-match reaction >>>morph.rxn_labels['gene-match'].add('rxn00456_c0') fails and throws an exception. add() is a set method and can't be used on dictionaries. (You could set an entry with real or arbitrary value to get around this if you really wished) Each inner dictionary is keyed with reaction_ids, hashed to tuples as such: (model_index, probability) Where reaction_id is a kbase reaction id with the compartment info appended to the end (e.g. rxn01316_c0), model_index is the index of the reaction in the objects['x_model'][modelreactions] list, and the probability is the reaction probability associated with each reaction from the probanno object. Reactions not in ProbAnno are given an arbitrary probability of -1.0 Example evaluations: >>>rxn_labels['gene-no-match']['rxn01316_c0'][0] evaluates to the index of rxn01316_c0 in morph.objects['trans_model']['modelreactions'] >>>rxn_labels['gene-no-match']['rxn01316_c0'][1] evaluates to the reaction probability of rxn01316_c0 >>>'rxn01316_c0' in rxn_labels['gene-no-match'] will evaluate True if the reaction is a gene-no-match reaction (an inner dict key) Note ---- Function Requirements: - morph.probanno is a ReactionProbabilities - morph.src_model, morph.recon_model, morph.trans_model are FBAModels - morph.ws_id is the ID of a readable/writeable service workspace Post-Condition ------- Morph a morph in which morph.rxn_labels holds a dictionary with the keys 'gene-match', gene-no-match', 'recon' and 'no-gene'. The value of each key holds a dictionary with 0 or more entries of the form: reaction_id -> (model_index, probability) morph.probhash contains a dictionary of reaction_ids (COMPARTMENT TRUNCATED) mapped to their probabilities e.g. rxn09876 -> 0.04545339 Examples -------- Given a morph of the form (only relevant attributes shown): >>>morph = Client.label_reactions(morph) would produce something like: probannows: 9145 ws_name: MMws235 src_modelws: 9145 src_model: 19 trans_model: 3 probhash: ['rxn05653', 'rxn12345', rxn59595', 'rxn45644' ... (more)] rxn_labels: ['gene-match', 'gene-no-match', 'no-gene', 'recon'] ws_id: 11444 recon_model: 4 probanno: 15 morph.objects = ['source_model', 'recon_model', 'trans_model', 'probanno'] morph.info = ['source_model', 'recon_model', 'trans_model', 'probanno'] These could be examined like so: >>>morph.rxn_labels['no-gene'].keys()[1] u'rxn10316_c0' >>>morph.rxn_labels['no-gene']['rxn10316_c0'][1] 0.444456666959 >>>'rxn10316_c0' in morph.rxn_labels['no-gene'] True """ # get reaction sets recon_dict = dict([(r.rxn_id(), r) for r in self.recon_model.get_reactions()]) trans_dict = dict([(r.rxn_id(), r) for r in self.trans_model.get_reactions()]) model_dict = dict([(r.rxn_id(), r) for r in self.src_model.get_reactions()]) # create the rxn_labels dictionary self.rxn_labels = { 'gene-no-match': dict(), 'gene-match': dict(), 'no-gene': dict(), 'recon': dict(), 'common': dict() } # Some reference sets all_reactions = set(model_dict.keys()).union(recon_dict.keys()) for rxn in all_reactions: if rxn in trans_dict and rxn in recon_dict: self.rxn_labels['common'][rxn] = (trans_dict[rxn], recon_dict[rxn]) if rxn in model_dict and rxn not in trans_dict: if rxn not in recon_dict: self.rxn_labels['gene-no-match'][rxn] = model_dict[rxn] else: self.rxn_labels['recon'][rxn] = recon_dict[rxn] if rxn in trans_dict: gpr = trans_dict[rxn].gpr if gpr.gpr_type == 'no-gene' and rxn not in recon_dict: self.rxn_labels['no-gene'][rxn] = trans_dict[rxn] else: if rxn in recon_dict: self.rxn_labels['gene-match'][rxn] = recon_dict[rxn] else: self.rxn_labels['gene-match'][rxn] = trans_dict[rxn] if rxn in recon_dict and rxn not in trans_dict and rxn not in model_dict: self.rxn_labels['recon'][rxn] = recon_dict[rxn] def build_supermodel(self): """ Sets morph.model to a superset of all reactions in morph.rxn_labels Note ---- Function Requirements: - morph.rxn_labels is a dictionary with the four keys ['gene-match', 'gene-no-match', 'recon', 'no-gene'], and it's values are dictionaries with entries of the form: reaction_id -> (model_index, probability) - morph.objects contains entries for the 'source_model' and 'recon_model' with data for the models in KBase (this is the output of the label_reactions(morph) function) Parameters ---------- morph: Morph The morph for which you want to build a super_model (initializing morph.model) Returns ------- Morph a morph object where morph.model, morph.ws_id forms a valid ObjectIdentity for a readable/writable KBase model object (the super-model) Examples -------- Given a morph like so (only relevant attributes shown): ws_name: MMws235 trans_model: 3 rxn_labels: ['gene-match', 'gene-no-match', 'no-gene', 'recon'] ws_id: 11444 morph.objects = ['source_model', 'recon_model', 'trans_model', 'probanno'] morph.model = None >>>morph = Client.build_supermodel(morph) would produce something like this: ws_name: MMws235 trans_model: 3 rxn_labels: ['gene-match', 'gene-no-match', 'no-gene', 'recon'] ws_id: 11444 morph.objects = ['source_model', 'recon_model', 'trans_model', 'probanno'] morph.model = 5 Where morph.model, morph.ws_id forms a valid ObjectIdentity for a model object in KBase (the super model) """ if self.merge_conflicts is None: self.merge_conflicts = [] src_rxns = dict([(r.rxn_id(), r) for r in self.src_model.get_reactions()]) super_rxns = dict() specials = list() # copy the trans model self.model = self.trans_model.copy(self.service, workspace_id=self.ws_id) # ----> # Adding reactions into the translation. # First, go through every reaction they have in common and adjust if # necessary: reactions_to_remove = [] adjustments = [] for rxn_id in self.rxn_labels['common']: trans_rxn = self.rxn_labels['common'][rxn_id][0] # MR recon_rxn = self.rxn_labels['common'][rxn_id][1] # MR merge_gpr = trans_rxn.gpr.merge(recon_rxn.gpr) direction = _general_direction(trans_rxn, recon_rxn) if trans_rxn.gpr != merge_gpr or trans_rxn.get_direction( ) != direction: self.merge_conflicts.append(rxn_id) super_rxns[rxn_id] = recon_rxn adjustments.append( (recon_rxn.get_removal_id(), direction, merge_gpr)) removal_id = trans_rxn.get_removal_id() reactions_to_remove.append(removal_id) # ----> # removes the rxns we need to remove in place vs. making a new copy self.service.remove_reactions_in_place(self.model, reactions_to_remove) # Next, add all the reactions that aren't already in the translation: # Add the GENE_NO_MATCH reactions: for rxn_id in self.rxn_labels['gene-no-match']: reaction = self.rxn_labels['gene-no-match'][rxn_id] # need to remove gene references to avoid miscounting a gene that actually belongs to source organism reaction.data['modelReactionProteins'] = [] if reaction.is_special_ref(): specials.append(reaction) else: super_rxns[rxn_id] = reaction # Add the RECON reactions: for rxn_id in self.rxn_labels['recon']: reaction = self.rxn_labels['recon'][rxn_id] if rxn_id in src_rxns: direction = _general_direction(reaction, src_rxns[rxn_id]) else: direction = reaction.get_direction() if reaction.is_special_ref(): specials.append(reaction) else: if rxn_id not in super_rxns: super_rxns[rxn_id] = reaction adjustments.append( (reaction.get_removal_id(), direction, reaction.gpr)) # ----> result = self.service.add_reactions_manually(self.model, super_rxns.values(), name='super_model') self.model = FBAModel(result[0], result[1], service=self.service) self.service.adjust_directions_and_gprs(self.model, adjustments) result = self.service.add_reactions_manually(self.model, specials, name='super_modelspc') self.model = FBAModel(result[0], result[1], service=self.service) def prepare_supermodel(self, fill_src=False): """ Composition of the first several steps in the algorithm 1) Fill the source model to media using probabilistic gapfilling (can be skipped if fill_src keyword arg is set to False) 2) Translate the src_model to a pouplate morph.trans_model 3) Draft reconstruction of target genome fills morph.recon_model field 4) label reactions in the morph (populates morph.rxn_labels) 5) Builds a super_model and puts it in the morph.model field. The model is now ready for the process_reactions function Note ---- Function Requirements: - morph.probanno, morph.probannows form a valid ObjectIdentity for a readable RxnProbs object in KBase - morph.src_model, morph.src_modelws form a valid ObjectIdentity for a readable model object in KBase - morph.media, morph.mediaws form a valid ObjectIdentity for a readable media object in KBase - morph.genome, morph.genomews form a valid ObjectIdentity for a readable genome object in KBase - morph.protcomp, morph.protcompws form a valid ObjectIdentity for a readable protein comparison object in KBase - morph.ws_id is the ID of a writeable KBase workspace Parameters ---------- morph: Morph An initialized Morph with the following Requirements: - morph.ws_id is a valid KBase workspace_id that user has permission to write to - morph has valid object identities for src_model, genome, probanno, protcomp (These 4 are object_ids, their ___ws counterparts are workspace_ids of user readable workspaces) fill_src: boolean,optional a boolean indicating that the src_model should first be filled using probabilistic gapfilling Optional, default is true. Returns ------- Morph A Morph with the following state changes: - morph.model has the object_id of the super_model in KBase - morph.rxn_labels has the labels for the reactions in the super model - morph.probhash has the probability hash for reactions related to Target genome - morph.trans_model has the object_id of the translated model - morph.recon model has the object_id of the reconstruction of Target Genome Examples -------- Suppose you have a morph initialized like so: (this is the output of Helpers.make_morph() ) >>> morph = make_morph() probannows: 9145 ws_name: MMws235 src_modelws: 9145 protcompws: 9145 src_model: 19 media: 18 removed_ids: None mediaws: 9145 trans_model: None probhash: None genomews: 9145 essential_ids: None genome: 3 rxn_labels: None model: None ws_id: 11444 recon_model: None probanno: 15 protcomp: 6 A call to Client.prepare_supermodel(morph) will return a morph of this sort of form: >>> morph = Client.prepare_supermodel(morph) probannows: 9145 ws_name: MMws235 src_modelws: 9145 protcompws: 9145 src_model: 19 media: 18 removed_ids: None mediaws: 9145 trans_model: 3 probhash: [u'rxn00001' ... u'rxn97854'] genomews: 9145 essential_ids: None genome: 3 rxn_labels: ['gene-no-much', 'gene-match', 'recon', 'no-gene'] model: 5 ws_id: 11444 recon_model: 4 probanno: 15 protcomp: 6 See Also -------- fill_src_to_media translate_features reconstruct_genome label_reactions build_supermodel This functions post condition preps the morph for the Client.process_reactions(morph) function """ if fill_src: self.fill_src_to_media() self.translate_features() self.reconstruct_genome() self.label_reactions() self.build_supermodel() def process_reactions(self, rxn_list=None, name=None, growth_condition=None, num_reactions=-1): if growth_condition is None: growth_condition = GrowthConditions.SimpleCondition( service=self.service) """ Attempts removal of rxn_list reactions from morph (i.e. morph.rxn_labels[label]) Attempts removal of each reaction , keeping it only if it is essential to the objective function. Populates morph.essential_ids with the reaction_ids that could not be removed without breaking the model. morph.removed_ids is populated with the ids of the reactions that were removed. Both are populated as a dictionary of reaction_ids to their model_index and probability (like the entries in rxn_labels). e.g. reaction_id -> (model_index, probability) if rxn_list is None, the function removes (in low to high probability order) gene-no-match reactions followed by no-gene reactions Controlling name and process_count parameters allows the user tocontrol the number of models created in the morph.ws_id Note ---- Function Requirements: - if rxn_list is None, rxn_labels['gene-no-match'] and rxn_labels['no-gene'] must be dictionaries with 0 or more entries of the form reaction_id -> (model_index, probability) - morph.model, morph.ws_id form a valid ObjectIdentity for a readable model object in KBase - morph.ws_id is the ID of a writeable KBase workspace Parameters ---------- morph: Morph The morph containing the model (morph.model) from which reactions will be removed rxn_list: list, optional A sorted list of tuples of the form (reaction_id, (model_index, probability)) which will be processed from morph,model (form is the output of removal_list() function) (if left out, all gene-no-match follwed by all no-gene reactions will be processed in low to high likelihood order) name: String, optional Setting name will begin all output model names with name. Default is MM output models are named as follows: str(name) + '-' + str(process_count) process_count: int, optional A number indicating how many reactions have been processed so far, used in nameing output models. Default is 0. output models are named as follows: str(name) + '-' + str(process_count) get_count: Boolean, optional A Boolean flag indicating whether the process_count should be returned with the morph (as a tuple). Used when not processing all reactions at once. Deafault is False Returns ------- Morph A morph with a new model, and essential_ids/removed)ids used to keep track of changes int (Only if get_count=True) process_count (number of models created, used for name managing) Examples -------- Given a morph of the form (only relevant attributes shown): ws_name: MMws235 rxn_labels: ['gene-match', 'gene-no-match', 'no-gene', 'recon'] ws_id: 11444 morph.model = 5 morph.essential_ids = None morph.removed_ids = None >>>morph = Client.process_reactions(morph, rxn_list=Client.removal_list(morph.rxn_labels['gene-no-match'], list_range=(0, 10))) would process the 10 least likely gene-no-match reactions, which might produce a morph like this: ws_name: MMws235 rxn_labels: ['gene-match', 'gene-no-match', 'no-gene', 'recon'] ws_id: 11444 morph.model = 5 morph.essential_ids = ['rxn10316_c0', 'rxn23434_c0', 'rxn78687_c0'] morph.removed_ids = ['rxn11123_c0', 'rxn34534_c0', 'rxn90565_c0', 'rxn78987_c0', 'rxn12321_c0', 'rxn89034_c0', 'rxn88888_c0'] where removal of one of the reactions given by a key in morph.essential_ids would result in a model that has an objective value of 0.000 in FBA simulation :param get_count: :param process_count: :param name: :param rxn_list: :param iterative_models: :param growth_condition: """ ws = self.ws_id # Sort by probanno. items() returns (K, V=(model_index, prob)) def get_key(item): return self.get_prob(item[0]) # label argument behavior if rxn_list is None: rxn_dict = self.rxn_labels['gene-no-match'] removal_list = sorted(rxn_dict.items(), key=get_key) rxn_dict = self.rxn_labels['no-gene'] removal_list += sorted(rxn_dict.items(), key=get_key) removal_list = [ r for r in removal_list if r[0] not in self.rxn_labels['common'] ] else: removal_list = rxn_list # instantiate lists only if needed if self.essential_ids is None: self.essential_ids = dict() if self.removed_ids is None: self.removed_ids = dict() # Give objs a general name if none is provided if name is None: name = 'MorphedModel' max = num_reactions >= 0 and num_reactions or len(removal_list) for i in range(max): removal_id = removal_list[i][1].get_removal_id() rxn = removal_list[i][0] if removal_id.startswith('rxn00000'): self.log.add('skip', [self.model, removal_list[i][1]], [None], context='process_reactions') continue print '\nReaction to remove: ' + str(removal_id) + " / " + str(rxn) # TODO Find someway to fix the behavior bug if model_id is not in ws, etc. info = self.service.remove_reaction(self.model, removal_id, output_id='morph_candidate') candidate_model = FBAModel(info[0], info[1], service=self.service) if growth_condition.evaluate({ 'morph': self, 'model': candidate_model }): # removed successfully self.log.add('Removed Reaction', [self.model, growth_condition.fba], [candidate_model], context='process reactions') # overwrite current morph with candidate info = self.service.copy_object( (candidate_model.object_id, candidate_model.workspace_id), (name, self.model.workspace_id)) self.model = FBAModel(info[0], info[1], service=self.service) self.removed_ids[removal_id] = removal_list[i][1] else: # essential self.log.add('Kept Reaction', [self.model, growth_condition.fba], [candidate_model], context='process reactions') self.essential_ids[removal_id] = removal_list[i][1] print self.log.actions[-1].type + ' ' + str( removal_id) + ', FBA was ' + str( growth_condition.fba.objective) return self def get_prob(self, rxn_id): ''' returns the probanno likelihood for a reaction in a morph ''' #TODO: Will Users ever have their own probannos? YES if self.probanno is None: # This means probabilistic annotations are not required, but used if present return -1.0 if self.probhash is None: self.probhash = self.probanno.probability_hash() try: result = self.probhash[rxn_id.split('_')[0]] except KeyError: result = -1.0 return result def translate_media(self, new_media): """ transfers a growing model to a new media and ensures growth in this media, gpafilling if necessary """ self.media = new_media if not self.runfba().objective > 0: prev_rxns = set(([r.rxn_id() for r in self.model.get_reactions()])) info = self.service.gapfill_model(self.model, self.media, workspace=self.ws_id) filled_model = FBAModel(info[0], info[1], service=self.service) filled_rxns = dict([(r.rxn_id(), r) for r in filled_model.get_reactions()]) new_reactions = set(filled_rxns.keys()) - prev_rxns for r in new_reactions: self.rxn_labels['no-gene'][r] = filled_rxns[r] # KBASE QUIRKS MAKE THIS LINE THE OPPOSITE OF WHAT WE WANT: self.model = filled_model assert self.runfba().objective > 0 def get_labels(self, reaction_ids): """ Given a set of reaction_ids, return the labels for the reactions :param reaction_ids: list<str> of reaction ids. e.g. 'rxn12345_c0' :return: dict<str, list<str>> of ids to list of labels """ result = dict() for r in reaction_ids: result[r] = [] for label in self.rxn_labels: if r in self.rxn_labels[label]: result[r].append(label) return result
class DCGame(Model): def __init__(self, adjMat, numVisibleColorNodes, numAdversarialNodes, inertia): self.adjMat = adjMat self.numVisibleColorNodes = numVisibleColorNodes self.numAdversarialNodes = numAdversarialNodes # self.adversarialNodes = [] self.visibleColorNodes = [] self.regularNodes = [] self.schedule = RandomActivation(self) self.numAgents = len(adjMat) self.inertia = inertia # if there are 20 consensus colors then a # terminal state is reached self.terminate = False self.time = 0 # logging information self.log = Log() ## temporarily added this for figuring out ## why visible nodes have no help self.hasConflict = False # convert adjMat to adjList def getAdjList(adjMat): adjList = {key: [] for key in range(self.numAgents)} for node in range(self.numAgents): adjList[node] = [ idx for idx, value in enumerate(adjMat[node]) if value == True ] return adjList self.adjList = getAdjList(self.adjMat) ############# designate adversarial ############# # (node, degree) node_deg = [(idx, count(adjMat[idx])) for idx in range(self.numAgents)] # select the top-k nodes with largest degrees as adversarial node_deg.sort(key=lambda x: x[1], reverse=True) self.adversarialNodes = [ item[0] for item in node_deg[:self.numAdversarialNodes] ] ############# designate visible nodes ############# availableNodes = shuffled(node_deg[self.numAdversarialNodes:]) self.visibleColorNodes = [ item[0] for item in availableNodes[:self.numVisibleColorNodes] ] self.regularNodes = [ n for n in range(self.numAgents) if n not in self.adversarialNodes ] # make sure we have 20 regular nodes assert len(self.regularNodes) == 20 # adversarial nodes and regular nodes should not overlap assert set(self.adversarialNodes) & set(self.regularNodes) == set() # visible nodes should belong to regular nodes assert set(self.visibleColorNodes) & set(self.regularNodes) == set( self.visibleColorNodes) # logging simulation configuration self.log.add("#visible nodes: " + str(self.visibleColorNodes)) self.log.add("#adversarial nodes: " + str(self.adversarialNodes)) self.log.add("#regular nodes: " + str(self.regularNodes) + '\n') ############# initialize all agents ############# for i in range(self.numAgents): # if i is a visible node isVisibleNode = i in self.visibleColorNodes # if i is an adversarial isAdversarial = i in self.adversarialNodes # make sure adversarial nodes are not intersected with visible nodes assert isVisibleNode & isAdversarial == False neighbors = self.adjList[i] # visible color nodes in i's neighbors vNode = list(set(neighbors) & set(self.visibleColorNodes)) # if i == 6: # print(vNode) inertia = self.inertia # print("Add agent:", (i, visibleNode, adversarial, neighbors, visibleColorNodes)) a = GameAgent(i, isVisibleNode, isAdversarial, neighbors, vNode, inertia, self) self.schedule.add(a) # instantiate all nodes' neighbors and visibleColorNodes for agent in self.schedule.agents: agent.instantiateNeighbors(self) agent.instantiateVisibleColorNodes(self) self.datacollector = DataCollector( model_reporters={ "red": getRed, "green": getGreen }, agent_reporters={"agent_color": lambda a: a.color}) # simulate the whole model for one step def step(self): # # # if either red or green reaches consensus, terminates! # # in terminal state we do not collect data if not self.terminate: self.datacollector.collect(self) self.schedule.step() return self.terminate def simulate(self, simulationTimes): for i in range(simulationTimes): # update model's time self.updateTime(i) terminate = self.step() if terminate: break # output log file to disk self.log.outputLog('result/simResult.txt') simulatedResult = self.datacollector.get_model_vars_dataframe() return simulatedResult # update model's clock def updateTime(self, t): self.time = t def setTerminal(self): assert self.terminate == False self.terminate = True def addRecord(self, msg): self.log.add(msg) # for degub purpose only def outputAdjMat(self, path): with open(path, 'w') as fid: for line in self.adjMat: # convert list of boolean values to string values tline = ["1" if item else "0" for item in line] fid.write(' '.join(tline) + '\n')
class DCGame(Model): def __init__(self, adjMat, G, numVisibleColorNodes, numAdversarialNodes, inertia, beta, delay, visibles, adversaries): self.adjMat = adjMat self.numVisibleColorNodes = numVisibleColorNodes self.numAdversarialNodes = numAdversarialNodes # self.adversarialNodes = [] self.visibleColorNodes = [] self.regularNodes = [] self.schedule = FollowVisibleActivation(self) self.numAgents = len(adjMat) self.inertia = inertia # if there are 20 consensus colors then a # terminal state is reached self.terminate = False self.time = 0 # logging information self.log = Log() ## temporarily added this for figuring out ## why visible nodes have no help self.hasConflict = False # randomize regular players (exclude visibles) # decision self.beta = beta # a amount of time to delay ordinary players' decision # ordinary players = players who are neither visibles # nor has any visibles in their neighbor self.delay = delay # total number of color changes in a game self.colorChanges = 0 # addded by Yifan self.reach_of_adversaries = 0 self.reach_of_visibles = 0 self.total_cnt_of_adversaries = 0 self.total_cnt_of_visibles = 0 self.graph = G # convert adjMat to adjList def getAdjList(adjMat): adjList = {key: [] for key in range(self.numAgents)} for node in range(self.numAgents): #adjList[node] = [idx for idx, value in enumerate(adjMat[node]) if value == True] adjList[node] = [ idx for idx, value in enumerate(adjMat[node]) if value == 'True' ] return adjList self.adjList = getAdjList(self.adjMat) #return the subset of L availableNodes in G with the largest number of distinct neighbors def getSubsetWithMaxDistinctNeighbors(availableNodes, G, L): acc = [] max_cnt = 0 local_cnt = 0 hasBeenConsidered = [False for i in range(self.numAgents)] graph = nx.convert.to_dict_of_lists(G) for subset in itertools.combinations(availableNodes, L): upper_bound = 0 for agent in subset: upper_bound += len(graph[agent]) if upper_bound < max_cnt: continue # compute reach for agent in subset: for neighbor in G.neighbors(agent): if neighbor not in subset and hasBeenConsidered[ neighbor] == False: local_cnt += 1 hasBeenConsidered[neighbor] = True if local_cnt > max_cnt: max_cnt = local_cnt acc.clear() for agent in subset: acc.append(agent) local_cnt = 0 hasBeenConsidered = [False for i in range(self.numAgents)] return acc ############# designate visible ############# # node_deg = [(idx, count(adjMat[idx])) for idx in range(self.numAgents)] # availableNodes = [item[0] for item in node_deg] # random.shuffle(availableNodes) # availableNodes.sort(key=lambda x : x) # self.visibleColorNodes = getSubsetWithMaxDistinctNeighbors(availableNodes, G, numVisibleColorNodes) # self.visibleColorNodes = [item for item in availableNodes[:self.numVisibleColorNodes]] self.visibleColorNodes = visibles # for visibleNode in self.visibleColorNodes: # availableNodes.remove(visibleNode) ############# designate adversarial ############### # self.adversarialNodes = getSubsetWithMaxDistinctNeighbors(availableNodes, G, numAdversarialNodes) # self.adversarialNodes = [item for item in availableNodes[:self.numAdversarialNodes]] self.adversarialNodes = adversaries # ================ prev version: designate adversarial and visible nodes =========== # node_deg = [(idx, count(adjMat[idx])) for idx in range(self.numAgents)] # all_nodes = [item[0] for item in node_deg] # random.shuffle(node_deg) # self.adversarialNodes = [item[0] for item in node_deg[:self.numAdversarialNodes]] # reach_of_adversaries = 0 # total_cnt_of_adversaries = 0 # hasBeenReached = dict.fromkeys(all_nodes, False) # for adversarialNode in self.adversarialNodes: # for neighbor in G.neighbors(adversarialNode): # if neighbor not in self.adversarialNodes: # total_cnt_of_adversaries += 1 # if neighbor not in self.adversarialNodes and hasBeenReached[neighbor] == False: # reach_of_adversaries += 1 # hasBeenReached[neighbor] = True # self.reach_of_adversaries = reach_of_adversaries # self.total_cnt_of_adversaries = total_cnt_of_adversaries # ############# designate visible nodes ############# # availableNodes = shuffled(node_deg[self.numAdversarialNodes:]) # self.visibleColorNodes = [item[0] for item in availableNodes[:self.numVisibleColorNodes]] # reach_of_visibles = 0 # total_cnt_of_visibles = 0 # hasBeenReached = dict.fromkeys(all_nodes, False) # for visibleColorNode in self.visibleColorNodes: # for neighbor in G.neighbors(visibleColorNode): # if neighbor not in self.adversarialNodes and neighbor not in self.visibleColorNodes: # total_cnt_of_visibles += 1 # if neighbor not in self.adversarialNodes and neighbor not in self.visibleColorNodes and hasBeenReached[neighbor] == False: # reach_of_visibles += 1 # hasBeenReached[neighbor] = True # self.reach_of_visibles = reach_of_visibles # self.total_cnt_of_visibles = total_cnt_of_visibles # =============================== self.regularNodes = [ n for n in range(self.numAgents) if n not in self.adversarialNodes ] # make sure we have 20 regular nodes # assert len(self.regularNodes) ==20 assert set(self.adversarialNodes) & set( self.visibleColorNodes) == set() # adversarial nodes and regular nodes should not overlap assert set(self.adversarialNodes) & set(self.regularNodes) == set() # visible nodes should belong to regular nodes assert set(self.visibleColorNodes) & set(self.regularNodes) == set( self.visibleColorNodes) # logging simulation configuration self.log.add("#visible nodes: " + str(self.visibleColorNodes)) self.log.add("#adversarial nodes: " + str(self.adversarialNodes)) self.log.add("#regular nodes: " + str(self.regularNodes) + '\n') ############# initialize all agents ############# for i in range(self.numAgents): # if i is a visible node isVisibleNode = i in self.visibleColorNodes # if i is an adversarial isAdversarial = i in self.adversarialNodes # make sure adversarial nodes are not intersected with visible nodes assert isVisibleNode & isAdversarial == False neighbors = self.adjList[i] # visible color nodes in i's neighbors vNode = list(set(neighbors) & set(self.visibleColorNodes)) inertia = self.inertia beta = self.beta # print("Add agent:", (i, visibleNode, adversarial, neighbors, visibleColorNodes)) a = GameAgent(i, isVisibleNode, isAdversarial, neighbors, vNode, inertia, beta, self) self.schedule.add(a) # instantiate all nodes' neighbors and visibleColorNodes for agent in self.schedule.agents: agent.instantiateNeighbors(self) agent.instantiateVisibleColorNodes(self) self.datacollector = DataCollector( model_reporters={ "red": getRed, "green": getGreen }, agent_reporters={"agent_color": lambda a: a.color}) def getReachOfAdversaries(self): return self.reach_of_adversaries def getReachOfVisibles(self): return self.reach_of_visibles def getTotalCntOfAdversaries(self): return self.total_cnt_of_adversaries def getTotalCntOfVisibles(self): return self.total_cnt_of_visibles # simulate the whole model for one step def step(self): # # # if either red or green reaches consensus, terminates! # # in terminal state we do not collect data if not self.terminate: self.datacollector.collect(self) self.schedule.step(self.delay) return self.terminate def simulate(self, simulationTimes): for i in range(simulationTimes): # update model's time # print("simulation time: " + str(i)) self.updateTime(i) terminate = self.step() if terminate: break #added by Yifan isRegWhite = False # output log file to disk if not terminate: # did not reach consensus for agent in self.schedule.agents: if not agent.isAdversarial and not agent.isVisibleNode and agent.color == "white": #at least one regular player remained white isRegWhite = True self.log.outputLog('result/simResult.txt') simulatedResult = self.datacollector.get_model_vars_dataframe() # print(simulatedResult) return (simulatedResult, isRegWhite) # update model's clock def updateTime(self, t): self.time = t def setTerminal(self): assert self.terminate == False self.terminate = True def addRecord(self, msg): self.log.add(msg) # for degub purpose only def outputAdjMat(self, path): with open(path, 'w') as fid: for line in self.adjMat: # convert list of boolean values to string values tline = ["1" if item else "0" for item in line] fid.write(' '.join(tline) + '\n')
class Logic: """Logic module for StarChart. Contains all methods called by main.py. Class variables: lock -- Holds the coordinates of the locked object, False if nothing is locked state -- Holds the screen UI is currently in """ #Initializing #TODO: make config file specific to plotter (config_plot.ini) #TODO: review previous todo #TODO: implement turns and orbits around planets when turns pass #states = main, terrain, battle, tech, etc.. state = State_Main state_chain = [state] Plot.start() Board.start(5) State_Main.init() Log.add("Program started") @classmethod def update_screen_size(cls): """ Updates values of width and height of the screen (x,y) in plotter. If the terminal's size has changed, updates size values in the plotter""" #TODO: mobve to plotter y, x = Plot.scr.getmaxyx() if (Plot.y != y or Plot.x != x): Plot.y, Plot.x = Plot.scr.getmaxyx() Plot.y -= 1 @classmethod def refresh(cls): """Clears screen to draw next frame.""" #TODO: move to plotter Logic.update_screen_size() Plot.scr.refresh() Plot.scr.clear() @classmethod def draw_state(cls): """Calls various methods in plotter module to draw the board and UI elements.""" #TODO: this method became superflous cls.state.plot() @classmethod def handle_lock(cls): locked = Board.terrain[Logic.lock[0]][Logic.lock[1]] if "Ship" in locked.identity: Plot.draw_lock(Board.terrain[Logic.lock[0]][Logic.lock[1]], Logic.lock[0], Logic.lock[1]) """ elif locked.search() == "Planet": Plot.draw_terrain(locked) """ @classmethod def get_input(cls): """Reads keyboard input from user""" return Plot.scr.getkey() @classmethod def handle_input(cls): """Takes the key pressed by the user and calls the appropiate method. Bindings: q -- Quits game / Quits Menu w,a,s,d -- Moves cursor / UI Selection e -- locks and unlocks cursor / Accept t y u g h j b n m """ #change will be False if there is no need to change stage #if there is, change[0] will contain a string indicating either the stage #or an instruction for moving in the stage chain (like "back") #further indexes will contain the necessary arguments for the transition, like the object key = cls.get_input() change = cls.state.handle_input(key) if change: if change[0] == "end": cls.end() elif change[0] == "terrain": cls.state = State_Terrain cls.state_chain.append(cls.state) cls.state.init(change[1]) elif change[0] in ["Minerals", "Humidity", "Elevation", "Info"]: cls.state = State_Terrain cls.state_chain[-1] = cls.state cls.state.change_view(change[0]) elif change[0] in ["Build", "Select", "Remove"]: cls.state.change_action(change[0]) elif change[0] == "back": cls.state_chain = cls.state_chain[:-1] cls.state = cls.state_chain[-1] elif change[0] == "main": cls.state_chain = cls.state_chain[0] cls.state = cls.state_chain[0] Log.add(str(cls.state_chain)) @classmethod def end(cls, exception=''): """Calls method to perform necessary steps for clean exit.""" Plot.end() if exception: Log.add(str(exception)) Log.add('Exiting program') Log.print() exit()
class Morph: # These are the allowed properties of a morph object. Values not specified # by user are set to None # This is an Abstract Object representing the Morph of a metabolic model # from one species to a close relative genome. It has information related to # the source model, the target genome, the reactions in the model as it is # morphed from source import to target, and the set of properties = {'src_model', 'genome', 'probanno', 'protcomp', 'model', 'rxn_labels', 'ws_id', 'ws_name', 'trans_model', 'recon_model', 'media', 'probhash', 'log'} def __init__(self, *arg_hash, **kwargs): """ Initiializes a Morph! A reasonable Morph needs each of the following set: src_model: (FBAModel) the model of the source organism genome: (Genome) the genome of the target organism probanno: (ReactionProbabilities) the likelihoods for KBase reactions in the target organism protcomp: (ProteomeComparison) the proteome comparison between source and target genomes media: (Media) the media for the source model and subsequent models :param arg_hash: a dictionary with the attributes desired as keys :param kwargs: keyword arguments :return: """ # TODO: EDIT THIS DOC LINE WITH THE TRUTH self.src_model = None self.model = None self.genome = None self.probanno = None self.protcomp = None self.model = None self.rxn_labels = None self.media = None self.recon_model = None self.trans_model = None self.probhash = None self.log = None self.ws_id = None self.ws_name = None self.essential_ids = None self.removed_ids = None for dictionary in arg_hash: for key in dictionary: if key in Morph.properties: setattr(self, key, dictionary[key]) for key in kwargs: if key in Morph.properties: setattr(self, key, kwargs[key]) for prop in Morph.properties: if not hasattr(self, prop): setattr(self, prop, None) if self.log is None: self.log = Log(self) if self.ws_id is None: self.ws_id, self.ws_name = service.init_workspace() self._check_rep() def _check_rep(self): if self.model is not None: assert isinstance(self.model, FBAModel), str(type(self.model)) if self.src_model is not None: assert isinstance(self.src_model, FBAModel), str(type(self.src_model)) if self.genome is not None: assert isinstance(self.genome, Genome), str(type(self.genome)) if self.media is not None: assert isinstance(self.media, Media), str(type(self.media)) if self.probanno is not None: assert isinstance(self.probanno, ReactionProbabilities), str(type(self.probanno)) if self.protcomp is not None: assert isinstance(self.protcomp, ProteomeComparison), str(type(self.protcomp)) if self.trans_model is not None: assert isinstance(self.trans_model, FBAModel), str(type(self.trans_model)) if self.recon_model is not None: assert isinstance(self.recon_model, FBAModel), str(type(self.recon_model)) def to_json(self): return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True) # Overridden Functions to produce unique output def __str__(self): output = '' for key in vars(self): attr = getattr(self, key) if isinstance(attr, dict): attr = attr.keys() if len(attr) < 100: output += str(key) + ': ' + str(attr) + '\n' else: output += str(key) + ': ' + str(attr[0:100]) + ' ... (more)\n' else: output += str(key) + ': ' + str(attr) + '\n' return output def __repr__(self): return str(self) def __unicode__(self): return unicode(str(self)) def fill_src_to_media(self): """ Gap-fills the Morphs source model to the provided media :return: None """ prev = FBAModel(self.src_model.object_id, self.src_model.workspace_id) self.src_model = self.src_model.copy(workspace_id=self.ws_id) result = service.gapfill_model(self.src_model, self.media, workspace=self.ws_id, rxn_probs=self.probanno) self.src_model = FBAModel(result[0], result[1]) self.log.add('gapfill', prev, self.src_model, context='fill_src_to_media') def runfba(self, model=None, media=None): """ Run FBA on the model in the Morph :param model: (optional) FBAModel, default is morph.model :param media: (optional) Media, default is morph.media :return: FBA """ if model is None: model = self.model if media is None: media = self.media objid, wsid = service.runfba(model, media, self.ws_id) return FBA(objid, wsid) def translate_features(self): """ Translate morph.model using ProteomeComparison (morph.procomp) to a translated model :return: None (sets morph.trans_model) """ prev = copy.deepcopy(self.trans_model) result = service.translate_model(self.src_model, self.protcomp, workspace=self.ws_id) self.trans_model = FBAModel(result[0], result[1]) self.log.add('model_translation', prev, self.trans_model, context='translate_features') def reconstruct_genome(self): """ Reconstruct the genome using automated reconstruction in the service form morph.genome :return: None (sets morph.recon_model) """ prev = copy.deepcopy(self.recon_model) result = service.reconstruct_genome(self.genome, workspace=self.ws_id) self.recon_model = FBAModel(result[0], result[1]) self.log.add('genome_reconstruction', prev, self.recon_model, context='reconstruct_genome') def label_reactions(self): """ Labels morph's reactions from translated model, reconstruction, and source Populates the rxn_labels attribute in the Morph object with a Dictionary of four dictionaries of reaction_id -> value tuples. The first level dicts are named with the keys: - gene-match - gene-no-match - no-gene - recon Populates morph.probhash with a dictionary of compartment-truncated reaction_ids to their probability relative to genome in question (derived from morph.probanno). Also populates morph.objects, morph.info with data from KBase objects (advanced use) Technical Details (Consult if you are encountering issues): For simplicity, an end user can treat the interiors of each dictionary like a set of reaction ids, but it is important to note the this is actually a nested dictionary with entries of the form: reaction_id -> (model_index, probability) Thus, some set behavior works, but some doesn't, the user must account for the fact that these are dictionaries: >>>'rxn09073_c0' in morph.rxn_labels['gene-no-match'] works and returns True or False, indicating whether or not rxn09073_c0 is a gene-no-match reaction >>>morph.rxn_labels['gene-match'].add('rxn00456_c0') fails and throws an exception. add() is a set method and can't be used on dictionaries. (You could set an entry with real or arbitrary value to get around this if you really wished) Each inner dictionary is keyed with reaction_ids, hashed to tuples as such: (model_index, probability) Where reaction_id is a kbase reaction id with the compartment info appended to the end (e.g. rxn01316_c0), model_index is the index of the reaction in the objects['x_model'][modelreactions] list, and the probability is the reaction probability associated with each reaction from the probanno object. Reactions not in ProbAnno are given an arbitrary probability of -1.0 Example evaluations: >>>rxn_labels['gene-no-match']['rxn01316_c0'][0] evaluates to the index of rxn01316_c0 in morph.objects['trans_model']['modelreactions'] >>>rxn_labels['gene-no-match']['rxn01316_c0'][1] evaluates to the reaction probability of rxn01316_c0 >>>'rxn01316_c0' in rxn_labels['gene-no-match'] will evaluate True if the reaction is a gene-no-match reaction (an inner dict key) Note ---- Function Requirements: - morph.probanno is a ReactionProbabilities - morph.src_model, morph.recon_model, morph.trans_model are FBAModels - morph.ws_id is the ID of a readable/writeable service workspace Post-Condition ------- Morph a morph in which morph.rxn_labels holds a dictionary with the keys 'gene-match', gene-no-match', 'recon' and 'no-gene'. The value of each key holds a dictionary with 0 or more entries of the form: reaction_id -> (model_index, probability) morph.probhash contains a dictionary of reaction_ids (COMPARTMENT TRUNCATED) mapped to their probabilities e.g. rxn09876 -> 0.04545339 Examples -------- Given a morph of the form (only relevant attributes shown): >>>morph = Client.label_reactions(morph) would produce something like: probannows: 9145 ws_name: MMws235 src_modelws: 9145 src_model: 19 trans_model: 3 probhash: ['rxn05653', 'rxn12345', rxn59595', 'rxn45644' ... (more)] rxn_labels: ['gene-match', 'gene-no-match', 'no-gene', 'recon'] ws_id: 11444 recon_model: 4 probanno: 15 morph.objects = ['source_model', 'recon_model', 'trans_model', 'probanno'] morph.info = ['source_model', 'recon_model', 'trans_model', 'probanno'] These could be examined like so: >>>morph.rxn_labels['no-gene'].keys()[1] u'rxn10316_c0' >>>morph.rxn_labels['no-gene']['rxn10316_c0'][1] 0.444456666959 >>>'rxn10316_c0' in morph.rxn_labels['no-gene'] True """ # get reaction sets recon_dict = dict([(r.rxn_id(), r) for r in self.recon_model.get_reactions()]) trans_dict = dict([(r.rxn_id(), r) for r in self.trans_model.get_reactions()]) model_dict = dict([(r.rxn_id(), r) for r in self.src_model.get_reactions()]) # create the rxn_labels dictionary self.rxn_labels = {'gene-no-match': dict(), 'gene-match': dict(), 'no-gene': dict(), 'recon': dict(), 'common': dict()} # Some reference sets all_reactions = set(model_dict.keys()).union(recon_dict.keys()) # TODO: runtime will make you cry for rxn in all_reactions: if rxn in trans_dict and rxn in recon_dict: self.rxn_labels['common'][rxn] = (trans_dict[rxn], recon_dict[rxn]) if rxn in model_dict and rxn not in trans_dict: if rxn not in recon_dict: self.rxn_labels['gene-no-match'][rxn] = model_dict[rxn] else: self.rxn_labels['recon'][rxn] = recon_dict[rxn] if rxn in trans_dict: gpr = trans_dict[rxn].gpr if gpr.gpr_type == 'no-gene' and rxn not in recon_dict: self.rxn_labels['no-gene'][rxn] = trans_dict[rxn] else: if rxn in recon_dict: self.rxn_labels['gene-match'][rxn] = recon_dict[rxn] else: self.rxn_labels['gene-match'][rxn] = trans_dict[rxn] if rxn in recon_dict and rxn not in trans_dict and rxn not in model_dict: self.rxn_labels['recon'][rxn] = recon_dict[rxn] def build_supermodel(self): """ Sets morph.model to a superset of all reactions in morph.rxn_labels Note ---- Function Requirements: - morph.rxn_labels is a dictionary with the four keys ['gene-match', 'gene-no-match', 'recon', 'no-gene'], and it's values are dictionaries with entries of the form: reaction_id -> (model_index, probability) - morph.objects contains entries for the 'source_model' and 'recon_model' with data for the models in KBase (this is the output of the label_reactions(morph) function) Parameters ---------- morph: Morph The morph for which you want to build a super_model (initializing morph.model) Returns ------- Morph a morph object where morph.model, morph.ws_id forms a valid ObjectIdentity for a readable/writable KBase model object (the super-model) Examples -------- Given a morph like so (only relevant attributes shown): ws_name: MMws235 trans_model: 3 rxn_labels: ['gene-match', 'gene-no-match', 'no-gene', 'recon'] ws_id: 11444 morph.objects = ['source_model', 'recon_model', 'trans_model', 'probanno'] morph.model = None >>>morph = Client.build_supermodel(morph) would produce something like this: ws_name: MMws235 trans_model: 3 rxn_labels: ['gene-match', 'gene-no-match', 'no-gene', 'recon'] ws_id: 11444 morph.objects = ['source_model', 'recon_model', 'trans_model', 'probanno'] morph.model = 5 Where morph.model, morph.ws_id forms a valid ObjectIdentity for a model object in KBase (the super model) """ src_rxns = dict([(r.rxn_id(), r) for r in self.src_model.get_reactions()]) super_rxns = dict() specials = list() # copy the trans model self.model = self.trans_model.copy() # ----> # Adding reactions into the translation. # First, go through every reaction they have in common and adjust if # necessary: reactions_to_remove = [] for rxn_id in self.rxn_labels['common']: trans_rxn = self.rxn_labels['common'][rxn_id][0] # MR recon_rxn = self.rxn_labels['common'][rxn_id][1] # MR merge_gpr = trans_rxn.gpr.merge(recon_rxn.gpr) direction = _general_direction(trans_rxn, recon_rxn) if trans_rxn.gpr != merge_gpr or trans_rxn.get_direction() != direction: super_rxns[rxn_id] = (recon_rxn.get_rxn_ref(), recon_rxn.get_comp_ref(), direction, str(merge_gpr)) removal_id = trans_rxn.get_removal_id() reactions_to_remove.append(removal_id) # ----> # removes the rxns we need to remove in place vs. making a new copy service.remove_reactions_in_place(self.model, reactions_to_remove) # Next, add all the reactions that aren't already in the translation: # Add the GENE_NO_MATCH reactions: for rxn_id in self.rxn_labels['gene-no-match']: reaction = self.rxn_labels['gene-no-match'][rxn_id] if reaction.is_special_ref(): specials.append(reaction) else: super_rxns[rxn_id] = (reaction.get_rxn_ref(), reaction.get_comp_ref(), reaction.get_direction()) adjustments = [] # Add the RECON reactions: for rxn_id in self.rxn_labels['recon']: reaction = self.rxn_labels['recon'][rxn_id] if rxn_id in src_rxns: direction = _general_direction(reaction, src_rxns[rxn_id]) else: direction = reaction.get_direction() if reaction.is_special_ref(): specials.append(reaction) else: if rxn_id not in super_rxns: super_rxns[rxn_id] = (reaction.get_rxn_ref(), reaction.get_comp_ref(), direction, str(reaction.gpr)) adjustments.append((reaction.get_removal_id(), reaction.gpr)) # ----> super_rxns = super_rxns.values() result = service.add_reactions(self.model, super_rxns, name='super_model') self.model = FBAModel(result[0], result[1]) service.adjust_gprs(self.model, adjustments) result = service.add_reactions_manually(self.model, specials, name='super_modelspc') self.model = FBAModel(result[0], result[1]) def prepare_supermodel(self, fill_src=False): """ Composition of the first several steps in the algorithm 1) Fill the source model to media using probabilistic gapfilling (can be skipped if fill_src keyword arg is set to False) 2) Translate the src_model to a pouplate morph.trans_model 3) Draft reconstruction of target genome fills morph.recon_model field 4) label reactions in the morph (populates morph.rxn_labels) 5) Builds a super_model and puts it in the morph.model field. The model is now ready for the process_reactions function Note ---- Function Requirements: - morph.probanno, morph.probannows form a valid ObjectIdentity for a readable RxnProbs object in KBase - morph.src_model, morph.src_modelws form a valid ObjectIdentity for a readable model object in KBase - morph.media, morph.mediaws form a valid ObjectIdentity for a readable media object in KBase - morph.genome, morph.genomews form a valid ObjectIdentity for a readable genome object in KBase - morph.protcomp, morph.protcompws form a valid ObjectIdentity for a readable protein comparison object in KBase - morph.ws_id is the ID of a writeable KBase workspace Parameters ---------- morph: Morph An initialized Morph with the following Requirements: - morph.ws_id is a valid KBase workspace_id that user has permission to write to - morph has valid object identities for src_model, genome, probanno, protcomp (These 4 are object_ids, their ___ws counterparts are workspace_ids of user readable workspaces) fill_src: boolean,optional a boolean indicating that the src_model should first be filled using probabilistic gapfilling Optional, default is true. Returns ------- Morph A Morph with the following state changes: - morph.model has the object_id of the super_model in KBase - morph.rxn_labels has the labels for the reactions in the super model - morph.probhash has the probability hash for reactions related to Target genome - morph.trans_model has the object_id of the translated model - morph.recon model has the object_id of the reconstruction of Target Genome Examples -------- Suppose you have a morph initialized like so: (this is the output of Helpers.make_morph() ) >>> morph = make_morph() probannows: 9145 ws_name: MMws235 src_modelws: 9145 protcompws: 9145 src_model: 19 media: 18 removed_ids: None mediaws: 9145 trans_model: None probhash: None genomews: 9145 essential_ids: None genome: 3 rxn_labels: None model: None ws_id: 11444 recon_model: None probanno: 15 protcomp: 6 A call to Client.prepare_supermodel(morph) will return a morph of this sort of form: >>> morph = Client.prepare_supermodel(morph) probannows: 9145 ws_name: MMws235 src_modelws: 9145 protcompws: 9145 src_model: 19 media: 18 removed_ids: None mediaws: 9145 trans_model: 3 probhash: [u'rxn00001' ... u'rxn97854'] genomews: 9145 essential_ids: None genome: 3 rxn_labels: ['gene-no-much', 'gene-match', 'recon', 'no-gene'] model: 5 ws_id: 11444 recon_model: 4 probanno: 15 protcomp: 6 See Also -------- fill_src_to_media translate_features reconstruct_genome label_reactions build_supermodel This functions post condition preps the morph for the Client.process_reactions(morph) function """ if fill_src: self.fill_src_to_media() self.translate_features() self.reconstruct_genome() self.label_reactions() self.build_supermodel() def process_reactions(self, rxn_list=None, name='', process_count=0, get_count=False, iterative_models=True, growth_condition=GrowthConditions.SimpleCondition()): """ Attempts removal of rxn_list reactions from morph (i.e. morph.rxn_labels[label]) Attempts removal of each reaction , keeping it only if it is essential to the objective function. Populates morph.essential_ids with the reaction_ids that could not be removed without breaking the model. morph.removed_ids is populated with the ids of the reactions that were removed. Both are populated as a dictionary of reaction_ids to their model_index and probability (like the entries in rxn_labels). e.g. reaction_id -> (model_index, probability) if rxn_list is None, the function removes (in low to high probability order) gene-no-match reactions followed by no-gene reactions Controlling name and process_count parameters allows the user tocontrol the number of models created in the morph.ws_id Note ---- Function Requirements: - if rxn_list is None, rxn_labels['gene-no-match'] and rxn_labels['no-gene'] must be dictionaries with 0 or more entries of the form reaction_id -> (model_index, probability) - morph.model, morph.ws_id form a valid ObjectIdentity for a readable model object in KBase - morph.ws_id is the ID of a writeable KBase workspace Parameters ---------- morph: Morph The morph containing the model (morph.model) from which reactions will be removed rxn_list: list, optional A sorted list of tuples of the form (reaction_id, (model_index, probability)) which will be processed from morph,model (form is the output of removal_list() function) (if left out, all gene-no-match follwed by all no-gene reactions will be processed in low to high likelihood order) name: String, optional Setting name will begin all output model names with name. Default is MM output models are named as follows: str(name) + '-' + str(process_count) process_count: int, optional A number indicating how many reactions have been processed so far, used in nameing output models. Default is 0. output models are named as follows: str(name) + '-' + str(process_count) get_count: Boolean, optional A Boolean flag indicating whether the process_count should be returned with the morph (as a tuple). Used when not processing all reactions at once. Deafault is False Returns ------- Morph A morph with a new model, and essential_ids/removed)ids used to keep track of changes int (Only if get_count=True) process_count (number of models created, used for name managing) Examples -------- Given a morph of the form (only relevant attributes shown): ws_name: MMws235 rxn_labels: ['gene-match', 'gene-no-match', 'no-gene', 'recon'] ws_id: 11444 morph.model = 5 morph.essential_ids = None morph.removed_ids = None >>>morph = Client.process_reactions(morph, rxn_list=Client.removal_list(morph.rxn_labels['gene-no-match'], list_range=(0, 10))) would process the 10 least likely gene-no-match reactions, which might produce a morph like this: ws_name: MMws235 rxn_labels: ['gene-match', 'gene-no-match', 'no-gene', 'recon'] ws_id: 11444 morph.model = 5 morph.essential_ids = ['rxn10316_c0', 'rxn23434_c0', 'rxn78687_c0'] morph.removed_ids = ['rxn11123_c0', 'rxn34534_c0', 'rxn90565_c0', 'rxn78987_c0', 'rxn12321_c0', 'rxn89034_c0', 'rxn88888_c0'] where removal of one of the reactions given by a key in morph.essential_ids would result in a model that has an objective value of 0.000 in FBA simulation :param get_count: :param process_count: :param name: :param rxn_list: :param iterative_models: :param growth_condition: """ ws = self.ws_id # Sort by probanno. items() returns (K, V=(model_index, prob)) def get_key(item): return self.get_prob(item[0]) # label argument behavior if rxn_list is None: rxn_dict = self.rxn_labels['gene-no-match'] removal_list = sorted(rxn_dict.items(), key=get_key) rxn_dict = self.rxn_labels['no-gene'] removal_list += sorted(rxn_dict.items(), key=get_key) # print "pre-filter: " + str(len(removal_list)) removal_list = [r for r in removal_list if r[0] not in self.rxn_labels['common']] # print "post-filter: " + str(len(removal_list)) else: removal_list = rxn_list # instantiate lists only if needed if self.essential_ids is None: self.essential_ids = dict() if self.removed_ids is None: self.removed_ids = dict() # Give objs a general name if none is provided if name == '': name = 'MM' for i in range(len(removal_list)): removal_id = removal_list[i][1].get_removal_id() rxn = removal_list[i][0] if removal_id.startswith('rxn00000'): self.log.add('skip', [self.model, removal_list[i][1]], [None], context='process_reactions', notes=str([process_count])) continue print '\nReaction to remove: ' + str(removal_id) + " / " + str(rxn) # TODO Find someway to fix the behavior bug if model_id is not in ws, etc. info = service.remove_reaction(self.model, removal_id, output_id=name + '-' + str(process_count)) new_model = FBAModel(info[0], info[1]) if iterative_models: process_count += 1 if growth_condition.evaluate({'morph': self, 'model': new_model}): # removed successfully self.log.add('Removed Reaction', [self.model, growth_condition.fba], [new_model], context='process reactions') self.model = new_model self.removed_ids[removal_id] = removal_list[i][1] else: # essential self.log.add('Kept Reaction', [self.model, growth_condition.fba], [new_model], context='process reactions') self.essential_ids[removal_id] = removal_list[i][1] print self.log.actions[-1].type + ' ' + str(removal_id) + ', FBA was ' + str(growth_condition.fba.objective) if get_count: return self, process_count return self def get_prob(self, rxn_id): ''' returns the probanno likelihood for a reaction in a morph ''' #TODO: Will Users ever have their own probannos? YES if self.probhash is None: self.probhash = self.probanno.probability_hash() try: result = self.probhash[rxn_id.split('_')[0]] except KeyError: result = -1.0 return result def translate_media(self, new_media): """ transfers a growing model to a new media and ensures growth in this media, gpafilling if necessary """ self.media = new_media if not self.runfba().objective > 0: prev_rxns = set(([r.rxn_id() for r in self.model.get_reactions()])) info = service.gapfill_model(self.model, self.media, workspace=self.ws_id, rxn_probs=self.probanno) filled_model = FBAModel(info[0], info[1]) filled_rxns = dict([(r.rxn_id(), r) for r in filled_model.get_reactions()]) new_reactions = set(filled_rxns.keys()) - prev_rxns for r in new_reactions: self.rxn_labels['no-gene'][r] = filled_rxns[r] # KBASE QUIRKS MAKE THIS LINE THE OPPOSITE OF WHAT WE WANT: self.model = filled_model assert self.runfba().objective > 0 def get_labels(self, reaction_ids): """ Given a set of reaction_ids, return the labels for the reactions :param reaction_ids: list<str> of reaction ids. e.g. 'rxn12345_c0' :return: dict<str, list<str>> of ids to list of labels """ result = dict() for r in reaction_ids: result[r] = [] for label in self.rxn_labels: if r in self.rxn_labels[label]: result[r].append(label) return result
def handle_input(cls, key): #TODO call handle_ui_input where handle_input is called, not inside here if key == "q": Log.add("Closing Program...") return ["end"] elif key in ['w','a','s','d']: cls.pan_camera(key) elif key == 'e': if cls.lock: Log.add("Trying to move ship...") if Board.terrain[cls.lock[0]][cls.lock[1]].identity[-1] == "Ship": Log.add("Ship id positive, moving...") Board.move(cls.lock[0], cls.lock[1], cls.posx, cls.posy) else: Log.add("Not a ship") cls.lock = False else: s = Board.terrain[cls.posx][cls.posy].identity if s != ["Empty"]: cls.lock = (cls.posx,cls.posy) Log.add("Locked onto " +str(cls.lock)) if "Planet" in s: planet = Board.terrain[cls.lock[0]][cls.lock[1]] cls.lock = False return ["terrain",planet] else: Log.add("Nothing to lock onto") return cls.handle_ui_input(key)
class Database: # init start def __init__(self,user='******'): self.currentUser = user self.dataLog = Log(user) # if no datadir, create new os.makedirs(dataPath, exist_ok=True) self.db = loadDB(self.dataLog) for id in self.db: if self.db[id]['user'] == user: self.id = id # init end def showUsers(self): print('\tid\tnavn') for id in self.db: print(f'\t{id}\t{self.db[id]["user"]}') def getUserName(self): return self.currentUser def choseUser(self, id): while True: try: self.dataLog = Log(self.db[id]["user"]) return self.db[id]["user"] except KeyError: return None def addWork(self): print(f'\n\tRegistrere arbeid for {self.currentUser}') isOK = input(f'\n\t1. ja\n\t2. nei\n\tskriv: ') if isOK != '1': return None while True: clearScreen() print(f'\n\tDato i dag:\t') print('\t' + getWeekDay(datetime.now())+ ' ' + datetime.now().strftime("%d.%m.%Y")) print('\n\tSkriv 1 for å bruke dagens dato'+ '\n\teller tast inn egen dato'+ '\n\tskriv 0 for å gå til hovedmeny') while True: date = input('\n\tFromatet må være slik: 01.01.2020'+ '\n\tskriv: ') if date == '1': date = datetime.now().strftime("%d.%m.%Y") break elif date == '0': return None else: try: datetime.strptime(date, '%d.%m.%Y') clearScreen() print('\n\tDato som er registrert:') print('\t' +getWeekDay(date)+ ' ' +date) print('\ter dette OK?') isOK = input('\t1. ja\n\t2. nei\n\tskriv: ') if isOK == '1': break except ValueError: input('\tUgyldig format'+ '\n\tTrykk Enter for å fortsette') clearScreen() while True: clearScreen() print('\n\tSkriv start tid\n\tFormatet må være slik:') start = input('\t08:00\n\tskriv: ') if len(start) != 5: input('\tUgyldig format'+ '\n\tTrykk Enter for å fortsette') continue try: datetime.strptime(start, '%H:%M') break except ValueError: input('\tUgyldig format'+ '\n\tTrykk Enter for å fortsette') continue while True: clearScreen() print('\n\tSkriv slutt tid\n\tFormatet må være slik:') end = input('\t16:00\n\tskriv: ') if len(end) != 5: input('\tUgyldig format'+ '\n\tTrykk Enter for å fortsette') continue if end.replace(':','') <= start.replace(':',''): print('\tslutt-tiden må være etter start-tiden') input('\tTrykk Enter for å gå tilbake til hovedmeny') return None try: datetime.strptime(end, '%H:%M') break except ValueError: input('\tUgyldig format'+ '\n\tTrykk Enter for å fortsette') continue clearScreen() # prompt user confirmation # check valid time if workSummary(date,start,end) == True: break else: continue clearScreen() y = date[6:] # year m = date[3:5] # month d = date[:2] # date # check if exist if self.db[self.id]['work'] == {}: self.db[self.id]['work'][y] = {} if y not in self.db[self.id]['work']: self.db[self.id]['work'][y] = {} if m not in self.db[self.id]['work'][y]: self.db[self.id]['work'][y][m] = {} # append work if d in self.db[self.id]['work'][y][m]: clearScreen() print('\n\tDu har allerede registrert arbeid for') print(f'\t{getWeekDay(date)} {date}\n') print('\tDitt gamle klokkeslett er') print(f"\tFra: {self.db[self.id]['work'][y][m][d]['start']}") print(f"\tTil: {self.db[self.id]['work'][y][m][d]['end']}") print(f'\n\tDitt nye klokkeslett er\n\tFra: {start}\n\tTil: {end}') choice = input('\n\tHvilket klokkeslett er riktig?'+ '\n\t1. det gamle\n\t2. det nye\n\tskriv: ') if choice == '2': clearScreen() print('\n\tOppdaterer nytt klokkeslett') sleep(1.5) self.db[self.id]['work'][y][m][d]['start'] = start self.db[self.id]['work'][y][m][d]['end'] = end else: clearScreen() print('\n\tIgnorerer nytt klokkeslett') sleep(1.5) return None else: clearScreen() print('\n\tOppdaterer nytt klokkeslett') sleep(1.5) self.db[self.id]['work'][y][m][d] = {'start':start,'end':end} self.dataLog.add(f'Added work {date} from {start} to {end}') updateDB(self.db) return None def removeWork(self): print(f'\n\tFjern arbeid for {self.currentUser}') isOK = input(f'\n\t1. ja\n\t2. nei\n\tskriv: ') if isOK != '1': return None M = nameMonths while True: clearScreen() y = input('\n\tSkriv inn årstall'+ '\n\tFor eksempel 2020\n\tskriv: ') clearScreen() if len(y) == 4 and y.isdecimal() and int(y) >= 2020: break while True: print('\n\tVelg en måned\n') for i in range(0,12,2): print('\t'+ str(i+1).rjust(2,' ') + ' ' + M[i].ljust(11) + str(i+2).rjust(2,' ') + ' ' + M[i+1].ljust(11)) m = input('\n\t0. gå tilake\n\tskriv: ') if int(m) >= 1 and int(m) <= 12: pass else: return None clearScreen() print('\n\tÅr ' + y + '\n\tMåned ' + nameMonths[int(m)-1]) try: # this only force try before starting loop self.db[self.id]['work'][y][m] while True: print('\n\tVelg en dato fra listen'+ ' som du ønsker å fjerne\n') for key in self.db[self.id]['work'][y][m]: print('\t'+str(int(key))+' '+nameMonths[int(m)-1]+ ' Fra: '+ self.db[self.id]['work'][y][m][key]['start']+ ' Til: '+ self.db[self.id]['work'][y][m][key]['end']) d = input('\n\t0. Gå tilbake\n\tskriv dato: ') if d == '0': clearScreen() break try: self.db[self.id]['work'][y][m][d.rjust(2, '0')] isOK = input('\tEr du sikker?\n\t1. ja\n\t2. nei'+ '\n\tskriv: ') if isOK == '1': del self.db[self.id]['work'][y][m][d.rjust(2, '0')] self.dataLog.add('Removed work '+d+'.'+ nameMonths[int(m)-1]+'.'+y) updateDB(self.db) clearScreen() else: clearScreen() break except KeyError: print('\n\tDu har ikke registrert arbeid for denne datoen') input('\tTrykk Enter for å gå videre') clearScreen() break except KeyError: print('\n\tDu har ikke registrert arbeid for denne måneden') input('\tTrykk Enter for å gå videre') clearScreen() def addUser(self): while True: print('\n\tSkriv inn brukernavnet som du\n\t'+ 'ønsker å legge til\n\teller skriv 0 for å gå tilbake') name = input('\tskriv: ') if name == '0': return None for value in self.db.values(): if name in value['user']: print(f'\tBrukernavn {name} eksisterer allerede') input('\tTrykk Enter for å gå videre') return None print(f'\n\t{name} blir lagt til, er dette OK?') choice = input('\t1. ja\n\t2. nei\n\tskriv: ') if choice == '1': self.dataLog.add(f'Added user {name}') if self.db == {}: self.db['1'] = {'user':name, 'work':{}} input('tom') else: for i in range(1, int(max(self.db))+2): if str(i) in self.db: continue else: self.db[str(i)] = {'user':name, 'work':{}} break updateDB(self.db) return None else: return None def removeUser(self, userID): if userID in self.db: print('\tvil du virkelig fjerne') print(f'\t{self.db[userID]["user"]}') choice = input('\t1. ja\n\t2. nei\n\tskriv: ') if choice == '1': self.dataLog.add(f'Removed user {self.db[userID]["user"]}') del self.db[userID] updateDB(self.db) else: print(f'\tBruker med id {userID} eksisterer ikke') input('\tTrykk Enter for å gå videre')
class car: def __init__(self, logger): self.connection = obd.Async() self.log = Log() self.logger = logger self.counter = 0 def getSpeed(self, r): self.log.add("SPEED", str(r.value)) self.count() def getFuelLevel(self, r): print(r.value) self.log.add("FUEL_LEVEL", str(r.value)) self.count() def getThrottlePosition(self, r): self.log.add("THROTTLE_POSITION", str(r.value)) self.count() def getCoolantTemp(self, r): self.log.add("COOLANT_TEMP", str(r.value)) self.count() def getOilPressure(self, r): self.log.add("RPM", str(r.value)) self.count() def getLoad(self, r): self.log.add("ENGINE_LOAD", str(r.value)) self.count() def getFuelRate(self, r): self.log.add("FUEL_RATE", str(r.value)) self.count() def count(self): self.counter += 1 if self.counter == 7: #number of callbacks self.logger.write(self.log.getLog()) self.counter = 0 def setupCallbacks(self): self.connection.watch(obd.commands.SPEED, callback=self.getSpeed) self.connection.watch(obd.commands.FUEL_LEVEL, callback=self.getFuelLevel) self.connection.watch(obd.commands.THROTTLE_POS, callback=self.getThrottlePosition) self.connection.watch(obd.commands.COOLANT_TEMP, callback=self.getCoolantTemp) self.connection.watch( obd.commands.RPM, callback=self.getOilPressure) # change to oil pressure self.connection.watch(obd.commands.ENGINE_LOAD, callback=self.getLoad) self.connection.watch(obd.commands.FUEL_RATE, callback=self.getFuelRate) def startLogging(self): self.connection.start() def stopLogging(self): self.connection.stop() def getStatus(self): return self.connection.status()
class Server(object): def __init__(self, peers, host, port): self.host = host self.port = port self.peer_id = '{}:{}'.format(host, port) self._logger = logging.getLogger(__name__) self._loop = asyncio.get_event_loop() self._pool = Pool(self, peers) # heartbeat constants and bookkeeping variables self._heartbeat_interval = 1000 # ms self._last_interval = None self._min_heartbeat_timeout = 2000 # ms self._max_heartbeat_timeout = 4000 # ms self._heartbeat_timeout = None self._last_heartbeat = None self.reset_heartbeat() self.reset_timeout() self._log = Log(Machine()) self.state = State.FOLLOWER self.term = 0 self.voted = None self.votes = set() self._pending_clients = {} self.handlers = {'append_entries_req': self.handle_append_entries_req, 'append_entries_resp': self.handle_append_entries_resp, 'request_vote_req': self.handle_request_vote_req, 'request_vote_resp': self.handle_request_vote_resp} def reset_heartbeat(self): self._last_heartbeat = self._loop.time() def reset_interval(self): self._last_interval = self._loop.time() def reset_timeout(self): self._heartbeat_timeout = randint(self._min_heartbeat_timeout, self._max_heartbeat_timeout) / 1000 @property def stale(self): return self._last_heartbeat + self._heartbeat_timeout < self._loop.time() @staticmethod def decode(data): return json.loads(data.decode()) @staticmethod def encode(data): return json.dumps(data).encode() def broadcast(self, request): for peer in self._pool: self.send_async(peer, request) @asyncio.coroutine def run(self): self.reset_interval() while True: self._logger.debug('state: {}, term: {}'.format(self.state, self.term)) if self.state == State.LEADER: self.append_entries() if self.state in (State.CANDIDATE, State.FOLLOWER) and self.stale: self.request_vote() yield from self.wait() @asyncio.coroutine def send(self, peer, request): """ Send a request to a peer (if available). """ transport = yield from peer.get_transport() if transport: transport.write(self.encode(request)) def send_async(self, peer, request): """ Schedule the execution """ asyncio.async(self.send(peer, request)) @asyncio.coroutine def wait(self): """ Wait for the next interval. """ tic = self._heartbeat_interval / 1000 - self._loop.time() + self._last_interval yield from asyncio.sleep(tic) self.reset_interval() def to_leader(self): self.append_entries() self.state = State.LEADER self.voted = None self.votes = set() for peer in self._pool: peer.match = -1 peer.next = self._log.index + 1 def to_follower(self, term): self.state = State.FOLLOWER self.term = term self.voted = None self.votes = set() def append_entries(self, peer=None): """ Append entries RPC. """ peers = self._pool.all() if peer is None else [peer] for peer in peers: log_entries = self._log[peer.next:] log_index, log_term, _ = self._log[peer.next - 1] request = {'rpc': 'append_entries_req', 'peer_id': self.peer_id, 'term': self.term, 'log_commit': self._log.commit, 'log_entries': log_entries, 'log_index': log_index, 'log_term': log_term, } self.send_async(peer, request) self._logger.debug('broadcasting append entries') def request_vote(self): """ Request vote RPC. """ self.reset_heartbeat() self.reset_timeout() self.state = State.CANDIDATE self.term += 1 self.voted = self.peer_id self.votes = set([self.peer_id]) request = {'rpc': 'request_vote_req', 'peer_id': self.peer_id, 'term': self.term, 'log_index': self._log.index, 'log_term': self._log.term, } self.broadcast(request) self._logger.debug('broadcasting request vote') def handle_peer(self, request): """ Dispatch requests to the appropriate handlers. """ if self.term < request['term']: self.to_follower(request['term']) return self.handlers[request['rpc']](request) def handle_append_entries_req(self, request): self._logger.debug('append entries request received') if request['term'] < self.term: return self.reset_heartbeat() log_index = request['log_index'] log_term = request['log_term'] if not self._log.match(log_index, log_term): return {'rpc': 'append_entries_resp', 'peer_id': self.peer_id, 'term': self.term, 'log_index': self._log.index, 'success': False } log_entries = request['log_entries'] self._log.append(log_index, log_entries) log_commit = request['log_commit'] if self._log.commit < log_commit: index = min(self._log.index, log_commit) self._log.commit = index self._log.apply(index) if not log_entries: # no need to answer, the peer might have committed return # new entries but has certainly not replicated new ones return {'rpc': 'append_entries_resp', 'peer_id': self.peer_id, 'term': self.term, 'log_index': self._log.index, 'log_term': self._log.term, 'success': True, } def handle_append_entries_resp(self, response): if response['success']: self._logger.debug('append entries succeeded') log_index = response['log_index'] log_term = response['log_term'] peer_id = response['peer_id'] self._pool[peer_id].match = log_index self._pool[peer_id].next = log_index + 1 if (self._log.commit < log_index and self._pool.ack(log_index) and log_term == self.term): self._log.commit = log_index results = self._log.apply(log_index) self.return_results(results) else: peer = self._pool[response['peer_id']] peer.next -= 1 self.append_entries(peer) # self._logger.debug('append entries failed') def handle_request_vote_req(self, request): self._logger.debug('request vote request received') if request['term'] < self.term: return log_index = request['log_index'] log_term = request['log_term'] peer_id = request['peer_id'] if self.voted in (None, peer_id) and self._log.match(log_index, log_term): granted = True self.reset_heartbeat() else: granted = False return {'rpc': 'request_vote_resp', 'peer_id': self.peer_id, 'term': self.term, 'granted': granted, } def handle_request_vote_resp(self, response): if self.term == response['term'] and response['granted']: self.votes.add(response['peer_id']) if self._pool.majority(len(self.votes)): self.to_leader() def handle_client(self, cmd, transport): self._log.add(self.term, cmd) self._pending_clients[(self.term, self._log.index)] = transport self.append_entries() def return_results(self, results): for result in results: term, index, result = result transport = self._pending_clients.pop((term, index)) transport.write(self.encode(result)) transport.close()
class DCGame(Model): def __init__(self, adjMat, visibles, adversaries): self.adjMat = adjMat #matrix that keeps track of all players and their neighbors self.schedule = SimultaneousActivation( self ) # An activation in which players' states are effectively updated simultaneously as opposed to sequentially self.numAgents = len(adjMat) self.terminate = False # if all non-adversarial players have reached consensus, terminal state is achieved self.time = 0 # logging information self.log = Log() # total number of color changes in a game self.colorChanges = 0 # convert adjMat to adjList def getAdjList(adjMat): adjList = {key: [] for key in range(self.numAgents)} for node in range(self.numAgents): #adjList[node] = [idx for idx, value in enumerate(adjMat[node]) if value == True] adjList[node] = [ idx for idx, value in enumerate(adjMat[node]) if value == 'True' ] return adjList self.adjList = getAdjList(self.adjMat) ############# designate visible, adversarial, and consensus nodes ############# self.visibleColorNodes = visibles self.adversarialNodes = adversaries self.consensusNodes = [ n for n in range(self.numAgents) if n not in self.adversarialNodes ] # adversarial nodes and regular nodes should not overlap assert set(self.adversarialNodes) & set(self.consensusNodes) == set() # visible nodes should belong to regular nodes assert set(self.visibleColorNodes) & set(self.consensusNodes) == set( self.visibleColorNodes) # logging simulation configuration self.log.add("#visible nodes: " + str(self.visibleColorNodes)) self.log.add("#adversarial nodes: " + str(self.adversarialNodes)) self.log.add("#consensus nodes: " + str(self.consensusNodes) + '\n') ############# initialize all agents ############# for i in range(self.numAgents): # if i is a visible node isVisibleNode = i in self.visibleColorNodes # if i is an adversarial isAdversarial = i in self.adversarialNodes # make sure adversarial nodes are not intersected with visible nodes assert isVisibleNode & isAdversarial == False neighbors = self.adjList[i] # visible color nodes in i's neighbors vNode = list(set(neighbors) & set(self.visibleColorNodes)) a = GameAgent(i, isVisibleNode, isAdversarial, neighbors, vNode, self) self.schedule.add(a) # instantiate all nodes' neighbors and visibleColorNodes for agent in self.schedule.agents: agent.instantiateNeighbors(self) agent.instantiateVisibleColorNodes(self) self.datacollector = DataCollector( model_reporters={ "red": getRed, "green": getGreen }, agent_reporters={"agent_color": lambda a: a.color}) # simulate the whole model for one step def step(self): # # # if either red or green reaches consensus, terminates! # # in terminal state we do not collect data if not self.terminate: self.datacollector.collect(self) self.schedule.step() return self.terminate def simulate(self, simulationTimes): for i in range(simulationTimes): self.updateTime(i) # update model's time terminate = self.step() if terminate: break #added by Yifan hasWhitePlayers = False if not terminate: # if consensus was not reached in the simulation for agent in self.schedule.agents: if not agent.isAdversarial and not agent.isVisibleNode and agent.color == "white": #at least one consensus player remained white hasWhitePlayers = True # output log file to disk self.log.outputLog('result/simResult.txt') simulatedResult = self.datacollector.get_model_vars_dataframe() return (simulatedResult, hasWhitePlayers) # update model's clock def updateTime(self, t): self.time = t def setTerminal(self): assert self.terminate == False self.terminate = True def addRecord(self, msg): self.log.add(msg) # for degub purpose only def outputAdjMat(self, path): with open(path, 'w') as fid: for line in self.adjMat: # convert list of boolean values to string values tline = ["1" if item else "0" for item in line] fid.write(' '.join(tline) + '\n')