def model_init(self, policy, kwargs): """ Init of the model, The provided implementation here assumes that `self.model_file` is set correctly. In case of using different vensim models for different policies, it is recomended to extent this method, extract the model file from the policy dict, set `self.model_file` to this file and then call this implementation through calling `super`. :param policy: a dict specifying the policy. In this implementation, this argument is ignored. :param kwargs: additional keyword arguments. In this implementation this argument is ignored. """ load_model(self.working_directory+self.model_file) #load the model debug("model initialized successfully") be_quiet() # minimize the screens that are shown try: initialTime = get_val('INITIAL TIME') finalTime = get_val('FINAL TIME') timeStep = get_val('TIME STEP') savePer = get_val('SAVEPER') if savePer > 0: timeStep = savePer self.runLength = int((finalTime - initialTime)/timeStep +1) except VensimWarning: raise EMAWarning(str(VensimWarning))
def _store_result(self, result): for outcome in self.outcomes: debug("storing {}".format(outcome)) try: outcome_res = result[outcome] except KeyError: ema_logging.debug("%s not in msi" % outcome) else: try: self.results[outcome][self.i-1, ] = outcome_res self.results[outcome].flush() except KeyError: data = np.asarray(outcome_res) shape = data.shape if len(shape)>2: raise EMAError(self.shape_error_msg.format(len(shape))) shape = list(shape) shape.insert(0, self.nr_experiments) shape = tuple(shape) fh = tempfile.TemporaryFile() self.results[outcome] = np.memmap(fh, dtype=data.dtype, shape=shape) self.results[outcome][:] = np.NAN self.results[outcome][self.i-1, ] = data self.results[outcome].flush()
def __init__(self, gui=False, thd=False): ''' Create a link with netlogo. Underneath, the netlogo jvm is started throuhg jpype. :param gui: boolean, if true run netlogo with gui, otherwise run in headless mode. Defaults to false. :param thd: boolean, if thrue start netlogo in 3d mode. Defaults to false ''' if not jpype.isJVMStarted(): # netlogo jars jars = [NETLOGO_HOME + r'/lib/scala-library.jar', NETLOGO_HOME + r'/lib/asm-all-3.3.1.jar', NETLOGO_HOME + r'/lib/picocontainer-2.13.6.jar', NETLOGO_HOME + r'/lib/log4j-1.2.16.jar', NETLOGO_HOME + r'/lib/jmf-2.1.1e.jar', NETLOGO_HOME + r'/lib/pegdown-1.1.0.jar', NETLOGO_HOME + r'/lib/parboiled-core-1.0.2.jar', NETLOGO_HOME + r'/lib/parboiled-java-1.0.2.jar', NETLOGO_HOME + r'/lib/mrjadapter-1.2.jar', NETLOGO_HOME + r'/lib/jhotdraw-6.0b1.jar', NETLOGO_HOME + r'/lib/quaqua-7.3.4.jar', NETLOGO_HOME + r'/lib/swing-layout-7.3.4.jar', NETLOGO_HOME + r'/lib/jogl-1.1.1.jar', NETLOGO_HOME + r'/lib/gluegen-rt-1.1.1.jar', NETLOGO_HOME + r'/NetLogo.jar', PYNETLOGO_HOME + r'/external_files/netlogoLink.jar'] # format jars in right format for starting java virtual machine # TODO the use of the jre here is only relevant under windows # apparently jars = ";".join(jars) jarpath = '-Djava.class.path={}'.format(jars) jvm_dll = NETLOGO_HOME + r'/jre/bin/client/jvm.dll' cwd = os.getcwd() os.chdir(NETLOGO_HOME) # jpype.startJVM(jvm_dll, jarpath) jpype.startJVM(jpype.getDefaultJVMPath(), jarpath) os.chdir(cwd) cwd = jpype.java.lang.System.getProperty("user.dir"); debug("jvm started") gui = jpype.java.lang.Boolean(gui) thd = jpype.java.lang.Boolean(thd) link = jpype.JClass('netlogoLink.NetLogoLink') self.link = link(gui, thd)
def find_box(self): ''' Execute one iteration of the PRIM algorithm. That is, find one box, starting from the current state of Prim. ''' # set the indices self._update_yi_remaining() if self.yi_remaining.shape[0] == 0: info("no data remaining") return # log how much data and how many coi are remaining info(self.message.format(self.yi_remaining.shape[0], self.determine_coi(self.yi_remaining))) # make a new box that contains all the remaining data points box = PrimBox(self, self.box_init, self.yi_remaining[:]) # perform peeling phase box = self._peel(box) debug("peeling completed") # perform pasting phase box = self._paste(box) debug("pasting completed") message = "mean: {0}, mass: {1}, coverage: {2}, density: {3} restricted_dimensions: {4}" message = message.format(box.mean[-1], box.mass[-1], box.coverage[-1], box.density[-1], box.res_dim[-1]) if (self.threshold_type==ABOVE) &\ (box.mean[-1] >= self.threshold): info(message) self.boxes.append(box) return box elif (self.threshold_type==BELOW) &\ (box.mean[-1] <= self.threshold): info(message) self.boxes.append(box) return box else: # make a dump box info('box does not meet threshold criteria, value is {}, returning dump box'.format(box.mean[-1])) box = PrimBox(self, self.box_init, self.yi_remaining[:]) self.boxes.append(box) return box
def read_cin_file(file_name): ''' read a .cin file :param file: location of the .cin file. :exception: raises a :class:`~EMAExceptions.VensimWarning` if the cin file cannot be read. ''' debug("executing COMMAND: SIMULATE>READCIN|"+file_name) try: command(r"SIMULATE>READCIN|"+file_name) except VensimWarning as w: debug(str(w)) raise w
def _paste(self, box): ''' Executes the pasting phase of the PRIM. Delegates pasting to data type specific helper methods.''' x = self.x[self.yi_remaining] mass_old = box.yi.shape[0]/self.n res_dim = sdutil._determine_restricted_dims(box.box_lims[-1], self.box_init) possible_pastes = [] for u in res_dim: debug("pasting "+u) dtype = self.x.dtype.fields.get(u)[0].name pastes = self._pastes[dtype](self, box, u) [possible_pastes.append(entry) for entry in pastes] if not possible_pastes: # there is no peel identified, so return box return box # determine the scores for each peel in order # to identify the next candidate box scores = [] for entry in possible_pastes: i, box_lim = entry obj = self.obj_func(self, self.y[box.yi], self.y[i]) non_res_dim = len(x.dtype.descr)-\ sdutil._determine_nr_restricted_dims(box_lim, self.box_init) score = (obj, non_res_dim, box_lim, i) scores.append(score) scores.sort(key=itemgetter(0,1), reverse=True) entry = scores[0] box_new, indices = entry[2:] mass_new = self.y[indices].shape[0]/self.n mean_old = np.mean(self.y[box.yi]) mean_new = np.mean(self.y[indices]) if (mass_new >= self.mass_min) &\ (mass_new > mass_old) &\ (mean_old <= mean_new): box.update(box_new, indices) return self._paste(box) else: #else return received box return box
def load_model(file_name): ''' load the model :param file: the location of the .vpm file to be loaded. :exception: raises a :class:`~EMAExceptions.VensimError` if the model cannot be loaded. .. note: only works for .vpm files ''' debug("executing COMMAND: SIMULATE>SPECIAL>LOADMODEL|"+file_name) try: command(r"SPECIAL>LOADMODEL|"+file_name) except VensimWarning as w: warning(str(w)) raise VensimError("vensim file not found")
def model_init(self, policy, kwargs): ''' Method called to initialize the model. :param policy: policy to be run. :param kwargs: keyword arguments to be used by model_intit. This gives users to the ability to pass any additional arguments. .. note:: This method should always be implemented. Although in simple cases, a simple pass can suffice. ''' self.policy = policy self.netlogo = pyNetLogo.NetLogoLink() debug("netlogo started") self.netlogo.load_model(self.working_directory+self.model_file) debug("model opened")
def _first_get_population(self): ''' called only once to initialize some stuff, returns a population. After the first call, _get_population is used instead. ''' debug("Start of evolution") self.pop = self.toolbox.population(self.pop_size) # Evaluate the entire population self.evaluate_population(self.pop, self.reporting_interval, self.toolbox, self.ensemble) # This is just to assign the crowding distance to the individuals tools.emo.assignCrowdingDist(self.pop) self.stats_callback(self.pop) self.stats_callback.log_stats(self.called) self.get_population = self._get_population
def run_simulation(file_name): ''' Convenient function to run a model and store the results of the run in the specified .vdf file. The specified output file will be overwritten by default :param file: the location of the outputfile :exception: raises a :class:`~EMAExceptions.VensimError` if running the model failed in some way. ''' try: debug(" executing COMMAND: SIMULATE>RUNNAME|"+file_name+"|O") command("SIMULATE>RUNNAME|"+file_name+"|O") debug(r"MENU>RUN|o") command(r"MENU>RUN|o") except VensimWarning as w: warning((str(w))) raise VensimError(str(w))
def __init__(self, working_directory, name): """interface to the model :param working_directory: working_directory for the model. :param name: name of the modelInterface. The name should contain only alphanumerical characters. .. note:: Anything that is relative to `self.working_directory` should be specified in `model_init` and not in `__init__`. Otherwise, the code will not work when running it in parallel. The reason for this is that the working directory is being updated by parallelEMA to the worker's separate working directory prior to calling `model_init`. """ super(VensimModelStructureInterface, self).__init__(working_directory, name) self.outcomes.append(Outcome('TIME' , time=True)) self.outcomes = list(self.outcomes) debug("vensim interface init completed")
def __init__(self, gui=False, thd=False): ''' Create a link with netlogo. Underneath, the netlogo jvm is started throuhg jpype. :param gui: boolean, if true run netlogo with gui, otherwise run in headless mode. Defaults to false. :param thd: boolean, if thrue start netlogo in 3d mode. Defaults to false ''' if not jpype.isJVMStarted(): # netlogo jars jars = [NETLOGO_HOME + r'/lib/scala-library.jar', NETLOGO_HOME + r'/lib/asm-all-3.3.1.jar', NETLOGO_HOME + r'/lib/picocontainer-2.13.6.jar', NETLOGO_HOME + r'/lib/log4j-1.2.16.jar', NETLOGO_HOME + r'/lib/jmf-2.1.1e.jar', NETLOGO_HOME + r'/lib/pegdown-1.1.0.jar', NETLOGO_HOME + r'/lib/parboiled-core-1.0.2.jar', NETLOGO_HOME + r'/lib/parboiled-java-1.0.2.jar', NETLOGO_HOME + r'/lib/mrjadapter-1.2.jar', NETLOGO_HOME + r'/lib/jhotdraw-6.0b1.jar', NETLOGO_HOME + r'/lib/quaqua-7.3.4.jar', NETLOGO_HOME + r'/lib/swing-layout-7.3.4.jar', NETLOGO_HOME + r'/lib/jogl-1.1.1.jar', NETLOGO_HOME + r'/lib/gluegen-rt-1.1.1.jar', NETLOGO_HOME + r'/NetLogo.jar', PYNETLOGO_HOME + r'/external_files/netlogoLink.jar'] # format jars in right format for starting java virtual machine # TODO the use of the jre here is only relevant under windows # apparently # might be solvable by setting netlogo home user.dir joined_jars = jar_separator.join(jars) jarpath = '-Djava.class.path={}'.format(joined_jars) jvm_handle = jpype.getDefaultJVMPath() jpype.startJVM(jvm_handle, jarpath, "-Xms128M","-Xmx1024m") jpype.java.lang.System.setProperty('user.dir', NETLOGO_HOME) if sys.platform=='darwin': jpype.java.lang.System.setProperty("java.awt.headless", "true"); debug("jvm started") link = jpype.JClass('netlogoLink.NetLogoLink') debug('NetLogoLink class found') if sys.platform == 'darwin' and gui: info('on mac only headless mode is supported') gui=False self.link = link(gui, thd) debug('NetLogoLink class instantiated')
def run_model(self, case): """ Method for running an instantiated model structure. This method should always be implemented. :param case: keyword arguments for running the model. The case is a dict with the names of the uncertainties as key, and the values to which to set these uncertainties. .. note:: This method should always be implemented. """ for key, value in case.iteritems(): try: self.netlogo.command(self.command_format.format(key, value)) except jpype.JavaException as e: warning('variable {0} throws exception: {}'.format((key, str(e)))) debug("model parameters set successfully") # finish setup and invoke run self.netlogo.command("setup") commands = [] fns = {} for outcome in self.outcomes: if outcome.time: name = outcome.name fn = r'{0}{3}{1}{2}'.format(self.working_directory, name, ".txt", os.sep) fns[name] = fn fn = '"{}"'.format(fn) fn = fn.replace(os.sep, '/') if self.netlogo.report('is-agentset? {}'.format(name)): # if name is name of an agentset, we # assume that we should count the total number of agents nc = r'{2} {0} {3} {4} {1}'.format(fn, name, "file-open", 'file-write', 'count') else: # it is not an agentset, so assume that it is # a reporter / global variable nc = r'{2} {0} {3} {1}'.format(fn, name, "file-open", 'file-write') commands.append(nc) c_start = "repeat {} [".format(self.run_length) c_end = "go ]" c_middle = " ".join(commands) command = " ".join((c_start, c_middle, c_end)) self.netlogo.command(command) # after the last go, we have not done a write for the outcomes # so we do that now self.netlogo.command(c_middle) self.netlogo.command("file-close-all") self._handle_outcomes(fns)
def run_model(self, case): """ Method for running an instantiated model structure. the provided implementation assumes that the keys in the case match the variable names in the Vensim model. If lookups are to be set specify their transformation from uncertainties to lookup values in the extension of this method, then call this one using super with the updated case dict. if you want to use cin_files, set the cin_file, or cin_files in the extension of this method to `self.cin_file`. :param case: the case to run .. note:: setting parameters should always be done via run_model. The model is reset to its initial values automatically after each run. """ if self.cin_file: try: read_cin_file(self.working_directory+self.cin_file) except VensimWarning as w: debug(str(w)) else: debug("cin file read successfully") for key, value in case.items(): set_value(key, value) debug("model parameters set successfully") debug("run simulation, results stored in " + self.working_directory+self.result_file) try: run_simulation(self.working_directory+self.result_file) except VensimError: raise results = {} error = False for output in self.outcomes: debug("getting data for %s" %output.name) result = get_data(self.working_directory+self.result_file, output.name ) debug("successfully retrieved data for %s" %output.name) if not result == []: if result.shape[0] != self.runLength: got = result.shape[0] data = np.empty((self.runLength)) data[:] = np.NAN data[0:result.shape[0]] = result result = data error = True if not output.time: result = [-1] else: result = result[0::self.step] try: results[output.name] = result except ValueError as e: print "what" raise e self.output = results if error: raise CaseError("run not completed, got %s, expected %s" % (got, self.runLength), case)
class EVO(NetLogoModelStructureInterface): model_file = r"/ModelSebastiaanGreeven.nlogo" run_length = 100 uncertainties = [ ParameterUncertainty((1.01, 1.03), 'ExpFactor'), ParameterUncertainty((0.8, 1.2), 'ImpactFactor'), ParameterUncertainty((0, 50), 'TimeHorizonGov1'), ParameterUncertainty((0, 50), 'TimeHorizonGov2'), ParameterUncertainty((0, 50), 'TimeHorizonGov3'), ParameterUncertainty((0, 50), 'TimeHorizonGov4'), ParameterUncertainty((0, 50), 'TimeHorizonGov5'), ParameterUncertainty((0, 50), 'TimeHorizonInd1'), ParameterUncertainty((0, 50), 'TimeHorizonInd2'), ParameterUncertainty((0, 50), 'TimeHorizonInd3'), ParameterUncertainty((0, 50), 'TimeHorizonInd4'), ParameterUncertainty((0, 50), 'TimeHorizonInd5'), ParameterUncertainty((0, 1), 'DemocraticValue1'), ParameterUncertainty((0, 1), 'DemocraticValue2'), ParameterUncertainty((0, 1), 'DemocraticValue3'), ParameterUncertainty((0, 1), 'DemocraticValue4'), ParameterUncertainty((0, 1), 'DemocraticValue5'), ParameterUncertainty((0, 20), 'SDTimeHorizonDistribution'), ParameterUncertainty((0.2, 1), 'MitigationEnforcementFactor'), ParameterUncertainty((0.5, 1), 'EffectInternationalPolicyOnIndividuals'), ParameterUncertainty((0.5, 1), 'EffectInternationalPolicyOnNationalPolicy'), ParameterUncertainty((0.01, 0.1), 'BaseChanceOfClimateDisaster'), ParameterUncertainty((0, 1), 'EffectOfClimateChangeOnClimateDisasters'), ParameterUncertainty((0, 0.30), 'InitialSeverityOfClimateDisaster'), ParameterUncertainty((0, 0.30), 'PredictionError'), CategoricalUncertainty(('1', '3', '5'), 'EmissionMemory'), CategoricalUncertainty(('5', '10', '15'), 'YearsBetweenInternationalNegotiations'), CategoricalUncertainty(('"Cooperative"', '"Prisoners"'), 'GameTheory'), CategoricalUncertainty(('1', '3', '5'), 'ClimateDisasterMemory'), CategoricalUncertainty(('True', 'False'), 'ClimateDisasterIncreaseMitigation') ] outcomes = [ Outcome('CumulativeGHGreduction', time=True), Outcome('AnnualGHGreduction', time=True), Outcome('TotalAgreementEffect', time=True), Outcome('BottomUpMitigationRatio', time=True), Outcome('TotalClimateDisasterEffect', time=True) ] nr_replications = 100 def __init__(self, working_directory, name, defaults={}): super(EVO, self).__init__(working_directory, name) self.oois = self.outcomes[:] temp_outcomes = [] for outcome in self.outcomes: temp_outcomes.append(Outcome(outcome.name + '_mean', time=True)) temp_outcomes.append(Outcome(outcome.name + '_std', time=True)) self.outcomes = temp_outcomes self.defaults = defaults unc_to_remove = self.defaults.keys() self.uncertainties = [ unc for unc in self.uncertainties if unc.name not in unc_to_remove ] def run_model(self, case): for key, value in self.defaults.items(): case[key] = value replications = defaultdict(list) for i in range(self.nr_replications): ema_logging.debug('running replication {}'.format(i)) self._run_case(case) for key, value in self.output.items(): replications[key].append(value) for key, value in replications.items(): data = np.asarray(value) self.output[key + '_mean'] = np.mean(data, axis=0) self.output[key + '_std'] = np.std(data, axis=0) def _run_case(self, case): """ Method for running an instantiated model structure. This method should always be implemented. :param case: keyword arguments for running the model. The case is a dict with the names of the uncertainties as key, and the values to which to set these uncertainties. .. note:: This method should always be implemented. """ for key, value in case.iteritems(): try: self.netlogo.command(self.command_format.format(key, value)) except jpype.JavaException as e: warning('variable {0} throws exception: {}'.format( (key, str(e)))) debug("model parameters set successfully") # finish setup and invoke run self.netlogo.command("setup") time_commands = [] end_commands = [] fns = {} for outcome in self.oois: name = outcome.name fn = r'{0}{3}{1}{2}'.format(self.working_directory, name, ".txt", os.sep) fns[name] = fn fn = '"{}"'.format(fn) fn = fn.replace(os.sep, '/') if self.netlogo.report('is-agentset? {}'.format(name)): # if name is name of an agentset, we # assume that we should count the total number of agents nc = r'{2} {0} {3} {4} {1}'.format(fn, name, "file-open", 'file-write', 'count') else: # it is not an agentset, so assume that it is # a reporter / global variable nc = r'{2} {0} {3} {1}'.format(fn, name, "file-open", 'file-write') if outcome.time: time_commands.append(nc) else: end_commands.append(nc) c_start = "repeat {} [".format(self.run_length) c_close = "go ]" c_middle = " ".join(time_commands) c_end = " ".join(end_commands) command = " ".join((c_start, c_middle, c_close)) debug(command) self.netlogo.command(command) # after the last go, we have not done a write for the outcomes # so we do that now self.netlogo.command(c_middle) # we also need to save the non time series outcomes self.netlogo.command(c_end) self.netlogo.command("file-close-all") self._handle_outcomes(fns)
def show_boxes_together(boxes, results, uv=[], filter=True): ''' This functions visually shows the size of a list of prim boxes. Each box has its own color. The dump box is not shown. The size of the boxes is normalized, where 0 is the lowest sampled value for each uncertainty and 1 is the highest sampled value for each uncertainty. his is visualized using a light grey background. :param boxes: the list of prim objects as returned by :func:`perform_prim`. :param results: the results as returnd by :meth:`perform_experiments` :param uv: the uncertainties to show in the plot. Defaults to an empty list, meaning all the uncertainties will be shown. If the list is not empty only the uncertainties specified in uv will be plotted. :param filter: boolean, if True, the uncertainties for which all the boxes equal the size of the dump box are not visualized (default=True) :rtype: a `figure <http://matplotlib.sourceforge.net/api/figure_api.html>`_ instance ''' experiments, results = results boxes = [element.box for element in boxes] #determine minima and maxima boxes = __normalize(boxes, experiments) dump_box = boxes[-1] boxes = boxes[0:-1] uncertainties = sort_uncertainities(experiments, boxes[0], dump_box) # uncertainties = [] # for entry in experiments.dtype.descr: # uncertainties.append(entry[0]) if not uv: uv = uncertainties #plot results figure = plt.figure() ax = figure.add_subplot(111) #iterate over uncertainties names = [] i = -1 for name in uncertainties: if name in uv: show_uncertainty = True if filter: show_uncertainty=False #determine whether to show for box in boxes: minimum = box[name][0] maximum = box[name][1] value = box.dtype.fields.get(name)[0] if value == 'object': debug("filtering name") debug(dump_box[name][0]) debug(minimum) a = dump_box[name][0] if len(minimum) == len(a): ans = np.all(np.equal(a, minimum)) else: ans = False if not ans: show_uncertainty = True break elif (minimum > dump_box[name][0]) or\ (maximum < dump_box[name][1]): show_uncertainty = True break if show_uncertainty: i+=1 names.append(name) #iterate over boxes for j, box in enumerate(boxes): if value == 'object': y = box[name][0] x = [i+0.1*(j+1) for entry in range(len(y))] ax.scatter(x,y,edgecolor=COLOR_LIST[j%len(COLOR_LIST)], facecolor=COLOR_LIST[j%len(COLOR_LIST)]) else: ax.plot([i+0.1*(j+1), i+0.1*(j+1)], box[name][:], c=COLOR_LIST[j%len(COLOR_LIST)]) rect = mpl.patches.Rectangle((-0.5, 0), i+1.5, 1, facecolor="#C0C0C0", alpha=0.25, edgecolor="#C0C0C0") ax.add_patch(rect) ax.set_xlim(xmin= -0.5, xmax=len(names)-0.5) ax.set_ylim(ymin=-0.2, ymax=1.2) ax.xaxis.set_ticks([x for x in range(len(names))]) xtickNames = plt.setp(ax, xticklabels = names) plt.setp(xtickNames, rotation=90, fontsize=12) ytickNames = ax.get_yticklabels() plt.setp(ytickNames, rotation=90, fontsize=12) ax.set_ylabel('normalized uncertainty bandwidth', rotation=90, fontsize=12) return figure