Пример #1
0
    def run_model(self, scenario, policy):
        """
        Method for running an instantiated model structure. 
        
        Parameters
        ----------
        scenario : Scenario instance
        policy : Policy instance
        
        
        """
        super(Model, self).run_model(scenario, policy)
        constants = {c.name: c.value for c in self.constants}
        experiment = combine(scenario, policy, constants)

        model_output = self.function(**experiment)

        # TODO: might it be possible to somehow abstract this
        # perhaps expose a get_data on modelInterface?
        # different connectors can than implement only this
        # get method
        results = {}
        for i, variable in enumerate(self.outcome_variables):
            try:
                value = model_output[variable]
            except KeyError:
                ema_logging.warning(variable + ' not found in model output')
                value = None
            except TypeError:
                value = model_output[i]
            results[variable] = value
        self.output = results
Пример #2
0
 def run_experiment(self, experiment):
     """
     Method for running an instantiated model structure. 
     
     Parameters
     ----------
     experiment : dict like
     
     
     """
     model_output = self.function(**experiment)
     
     # TODO: might it be possible to somehow abstract this
     # perhaps expose a get_data on modelInterface?
     # different connectors can than implement only this
     # get method
     results  = {}
     for i, variable in enumerate(self.outcome_variables):
         try:
             value = model_output[variable]
         except KeyError:
             ema_logging.warning(variable +' not found in model output')
             value  = None
         except TypeError:
             value = model_output[i]
         results[variable] = value
     return results
Пример #3
0
    def run_model(self, scenario, policy):
        """
        Method for running an instantiated model structure. 
        
        Parameters
        ----------
        scenario : Scenario instance
        policy : Policy instance
        
        
        """
        super(Model, self).run_model(scenario, policy)
        constants = {c.name: c.value for c in self.constants}
        experiment = combine(scenario, policy, constants)

        model_output = self.function(**experiment)

        # TODO: might it be possible to somehow abstract this
        # perhaps expose a get_data on modelInterface?
        # different connectors can than implement only this
        # get method
        results = {}
        for i, variable in enumerate(self.outcome_variables):
            try:
                value = model_output[variable]
            except KeyError:
                ema_logging.warning(variable + " not found in model output")
                value = None
            except TypeError:
                value = model_output[i]
            results[variable] = value
        self.output = results
Пример #4
0
 def model_init(self, policy, kwargs):
     '''initializes the model'''
     
     try:
         self.model_file = policy['file']
     except KeyError:
         ema_logging.warning("key 'file' not found in policy")
     super(FluModel, self).model_init(policy, kwargs)
Пример #5
0
    def __init__(self, gui=False, thd=False, netlogo_home=None,
                 netlogo_version=None, jvm_home=None):
        '''

        Create a link with NetLogo. Underneath, the NetLogo JVM is started
        through Jpype.


        :param gui: boolean, if true run NetLogo with gui, otherwise run in 
                    headless mode. Defaults to false.
        :param thd: boolean, if true start NetLogo in 3d mode. Defaults to 
                    false
        :param nl_dir: string - full path to NetLogo .exe directory, use if
                    NetLogo is not in the default location
        :param nl_version: string - NetLogo version under nl_dir (5.2 or 6.0)

        '''
        if not netlogo_home:
            netlogo_home = get_netlogo_home()
        if not netlogo_version:
            netlogo_version = establish_netlogoversion(netlogo_home)
        if not jvm_home:
            jvm_home = jpype.get_default_jvm_path()

        if not jpype.isJVMStarted():
            jars = find_jars(netlogo_home)
            jars.append(os.path.join(PYNETLOGO_HOME,
                                     'java', 'netlogoLink_combined.jar'))
            joined_jars = jar_sep[sys.platform].join(jars)
            jarpath = '-Djava.class.path={}'.format(joined_jars)
            try:
                debug("starting jvm: {} {}".format(jvm_home, jarpath))
                jpype.startJVM(jvm_home, jarpath)
                debug("JVM started")
            except RuntimeError as e:
                warning('failed to start JVM using jvm_home')
                raise e
            #jpype.java.lang.System.setProperty('user.dir', netlogo_home)
            if sys.platform == 'darwin':
                debug('set state to headless on mac os')
                jpype.java.lang.System.setProperty("java.awt.headless", "true")

        try:
            link = jpype.JClass(module_name[netlogo_version])
        except Exception as e:
            ema_logging.warning(
                "can't find class for netlogo version"+netlogo_version)
            raise e
        debug('NetLogoLink class found')

        if sys.platform == 'darwin' and gui:
            info('on mac only Headless mode is supported')
            gui = False

        self.link = link(jpype.java.lang.Boolean(gui),
                         jpype.java.lang.Boolean(thd))
        debug('NetLogoLink class instantiated')
Пример #6
0
def set_fig_to_bw(fig,
                  style=HATCHING,
                  line_style='continuous',
                  all_colors=None):
    """
    TODO it would be nice if for lines you can select either markers, gray 
    scale, or simple black
    
    Take each axes in the figure and transform its content to black and white. 
    Lines are tranformed based on different line styles. Fills such as can 
    be used in `meth`:envelopes are gray-scaled. Heathmaps are also gray-scaled.
    
    
    derived from and expanded for my use from:
    http://stackoverflow.com/questions/7358118/matplotlib-black-white-colormap-with-dashes-dots-etc
    
    Parameters
    ----------
    fig : figure
          the figure to transform to black and white
    style : {HATCHING, GREYSCALE}
            parameter controlling how collections are transformed.
    line_style: str
                linestyle to use for converting, can be continuous, black
                or None  
    
    """
    all_colors = _identify_colors(fig)

    if len(all_colors) > len(bw_mapping):
        mapping_cycle = itertools.cycle(bw_mapping)
        ema_logging.warning(
            'more colors used than provided in B&W mapping, cycling over mapping'
        )
    else:
        mapping_cycle = bw_mapping
    colormap = dict(zip(all_colors, mapping_cycle))
    ema_logging.debug(colormap.keys())

    max_shade = 0.9
    for i, color in enumerate(colormap.keys()):
        relative_color = max_shade * ((i + 1) / len(all_colors))
        colormap[color]['fill'] = str(relative_color)

    for ax in fig.get_axes():
        set_ax_lines_bw(ax, colormap)
        set_ax_patches_bw(ax, colormap)
        set_ax_collections_to_bw(ax, style, colormap)
        set_ax_legend_to_bw(ax, style, colormap)

    set_legend_to_bw(fig.legends, style, colormap)
Пример #7
0
def set_fig_to_bw(fig, style=HATCHING,
                  line_style='continuous', all_colors=None):
    """
    TODO it would be nice if for lines you can select either markers, gray
    scale, or simple black

    Take each axes in the figure and transform its content to black and white.
    Lines are tranformed based on different line styles. Fills such as can
    be used in `meth`:envelopes are gray-scaled. Heathmaps are also gray-scaled.


    derived from and expanded for my use from:
    http://stackoverflow.com/questions/7358118/matplotlib-black-white-colormap-with-dashes-dots-etc

    Parameters
    ----------
    fig : figure
          the figure to transform to black and white
    style : {HATCHING, GREYSCALE}
            parameter controlling how collections are transformed.
    line_style: str
                linestyle to use for converting, can be continuous, black
                or None

    """
    all_colors = _identify_colors(fig)

    if len(all_colors) > len(bw_mapping):
        mapping_cycle = itertools.cycle(bw_mapping)
        ema_logging.warning(
            'more colors used than provided in B&W mapping, cycling over mapping')
    else:
        mapping_cycle = bw_mapping
    colormap = dict(zip(all_colors, mapping_cycle))
    ema_logging.debug(colormap.keys())

    max_shade = 0.9
    for i, color in enumerate(colormap.keys()):
        relative_color = max_shade * ((i + 1) / len(all_colors))
        colormap[color]['fill'] = str(relative_color)

    for ax in fig.get_axes():
        set_ax_lines_bw(ax, colormap)
        set_ax_patches_bw(ax, colormap)
        set_ax_collections_to_bw(ax, style, colormap)
        set_ax_legend_to_bw(ax, style, colormap)

    set_legend_to_bw(fig.legends, style, colormap)
Пример #8
0
def _set_ax_polycollection_to_bw(collection, ax, style, colormap):
    '''helper function for converting a polycollection to black and white
    
    Parameters
    ----------
    collection : polycollection
    ax : axes
    style : {GREYSCALE, HATCHING}
    colormap : dict
               mapping of color to B&W rendering

    
    '''

    if style == GREYSCALE:
        color_converter = ColorConverter()
        for polycollection in ax.collections:
            orig_color = polycollection._facecolors_original

            try:
                mapping = colormap[orig_color]
            except:
                ema_logging.warning(
                    'no mapping specified for color: {}'.format(orig_color))
            else:
                new_color = color_converter.to_rgba(mapping['fill'])
                new_color = np.asarray([new_color])
                polycollection.update({'facecolors': new_color})
                polycollection.update({'edgecolors': new_color})
    elif style == HATCHING:
        orig_color = collection._facecolors_original

        try:
            mapping = colormap[orig_color]
        except:
            ema_logging.warning(
                'no mapping specified for color: {}'.format(orig_color))
        else:
            collection.update({'facecolors': 'none'})
            collection.update({'edgecolors': 'white'})
            collection.update({'alpha': 1})

            for path in collection.get_paths():
                p1 = mpl.patches.PathPatch(path,
                                           fc="none",
                                           hatch=colormap[orig_color]['hatch'])
                ax.add_patch(p1)
                p1.set_zorder(collection.get_zorder() - 0.1)
Пример #9
0
def _set_ax_polycollection_to_bw(collection, ax, style, colormap):
    '''helper function for converting a polycollection to black and white

    Parameters
    ----------
    collection : polycollection
    ax : axes
    style : {GREYSCALE, HATCHING}
    colormap : dict
               mapping of color to B&W rendering


    '''

    if style == GREYSCALE:
        color_converter = ColorConverter()
        for polycollection in ax.collections:
            orig_color = polycollection._original_facecolor

            try:
                mapping = colormap[orig_color]
            except BaseException:
                ema_logging.warning(
                    'no mapping specified for color: {}'.format(orig_color))
            else:
                new_color = color_converter.to_rgba(mapping['fill'])
                new_color = np.asarray([new_color])
                polycollection.update({'facecolors': new_color})
                polycollection.update({'edgecolors': new_color})
    elif style == HATCHING:
        orig_color = collection._original_facecolor

        try:
            mapping = colormap[orig_color]
        except BaseException:
            ema_logging.warning(
                'no mapping specified for color: {}'.format(orig_color))
        else:
            collection.update({'facecolors': 'none'})
            collection.update({'edgecolors': 'white'})
            collection.update({'alpha': 1})

            for path in collection.get_paths():
                p1 = mpl.patches.PathPatch(path, fc="none",
                                           hatch=colormap[orig_color]['hatch'])
                ax.add_patch(p1)
                p1.set_zorder(collection.get_zorder() - 0.1)
Пример #10
0
def set_ax_lines_bw(ax, colormap, line_style='continuous'):
    """
    Take each Line2D in the axes, ax, and convert the line style to be 
    suitable for black and white viewing.
    
    Derived from and expanded for use in the EMA workbench from:
    http://stackoverflow.com/questions/7358118/matplotlib-black-white-colormap-with-dashes-dots-etc
    
    Parameters
    ----------
    ax : axes
         The ax of which the lines needs to be transformed to B&W. Lines are 
         transformed to different line styles.
    colormap : dict 
    line_style: str
                linestyle to use for converting, can be continuous, black
                or None
                
    # TODO:: None is strange as a value, and should be field based, can than 
    # replace if structure with dict based functions
    
    """

    for line in ax.get_lines():
        orig_color = line.get_color()
        try:
            mapping = colormap[orig_color]
        except:
            ema_logging.warning(
                'no mapping specified for color: {}'.format(orig_color))
        else:
            if line_style == 'continuous':
                line.set_color('black')
                alpha = 1 / (math.log(len(ax.get_lines())) + 1)
                line.set_alpha(alpha)
            elif line_style == 'black':
                line.set_color('black')
                line.set_alpha(0.5)
            else:
                line.set_color('black')
                line.set_dashes(mapping['dash'])
                line.set_marker(mapping['marker'])
                line.set_alpha(1)
                line.set_markersize(MARKERSIZE)
def set_ax_lines_bw(ax, colormap, line_style='continuous'):
    """
    Take each Line2D in the axes, ax, and convert the line style to be 
    suitable for black and white viewing.
    
    Derived from and expanded for use in the EMA workbench from:
    http://stackoverflow.com/questions/7358118/matplotlib-black-white-colormap-with-dashes-dots-etc
    
    Parameters
    ----------
    ax : axes
         The ax of which the lines needs to be transformed to B&W. Lines are 
         transformed to different line styles.
    colormap : dict 
    line_style: str
                linestyle to use for converting, can be continuous, black
                or None
                
    # TODO:: None is strange as a value, and should be field based, can than 
    # replace if structure with dict based functions
    
    """

    for line in ax.get_lines():
        orig_color = line.get_color()
        try:
            mapping = colormap[orig_color]
        except:
            ema_logging.warning('no mapping specified for color: {}'.format(orig_color))
        else:
            if line_style == 'continuous':
                line.set_color('black')
                alpha = 1/(math.log(len(ax.get_lines()))+1)
                line.set_alpha(alpha)
            elif line_style == 'black':
                line.set_color('black')
                line.set_alpha(0.5)
            else:
                line.set_color('black')
                line.set_dashes(mapping['dash'])
                line.set_marker(mapping['marker'])
                line.set_alpha(1)
                line.set_markersize(MARKERSIZE)
    def test_log_messages(self):
        ema_logging.log_to_stderr(ema_logging.DEBUG)
        
        with mock.patch('ema_workbench.util.ema_logging._logger') as mocked_logger:
            message = 'test message'
            ema_logging.debug(message)
            mocked_logger.debug.assert_called_with(message)

            ema_logging.info(message)
            mocked_logger.info.assert_called_with(message)
            
            ema_logging.warning(message)
            mocked_logger.warning.assert_called_with(message)
            
            ema_logging.error(message)
            mocked_logger.error.assert_called_with(message)
            
            ema_logging.exception(message)
            mocked_logger.exception.assert_called_with(message)
            
            ema_logging.critical(message)
            mocked_logger.critical.assert_called_with(message)            
Пример #13
0
    def test_log_messages(self):
        ema_logging.log_to_stderr(ema_logging.DEBUG)

        with mock.patch(
                'ema_workbench.util.ema_logging._logger') as mocked_logger:
            message = 'test message'
            ema_logging.debug(message)
            mocked_logger.debug.assert_called_with(message)

            ema_logging.info(message)
            mocked_logger.info.assert_called_with(message)

            ema_logging.warning(message)
            mocked_logger.warning.assert_called_with(message)

            ema_logging.error(message)
            mocked_logger.error.assert_called_with(message)

            ema_logging.exception(message)
            mocked_logger.exception.assert_called_with(message)

            ema_logging.critical(message)
            mocked_logger.critical.assert_called_with(message)
Пример #14
0
    def run_experiment(self, experiment):
        '''
        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. 
        '''

        #NetLogo agent attributes to be passed to Python well objects
        #when new wells are created in NetLogo
        nl_read_sys_attribs = ['who', 'xcor', 'ycor']
        nl_read_well_attribs = [
            'who', 'xcor', 'ycor', 'IsCold', 'z0', 'FilterLength', 'T_inj', 'Q'
        ]

        #NetLogo agent attributes to be updated by the Python objects after each period
        nl_update_well_attribs = ['T_modflow', 'H_modflow']
        nl_update_globals = ['ztop', 'Laquifer']

        self.netlogo.command('setup')

        for key, value in experiment.items():
            if key in self.NetLogo_uncertainties:
                try:
                    self.netlogo.command(self.command_format.format(
                        key, value))
                except jpype.JavaException as e:
                    warning('Variable {0} throws exception: {}'.format(
                        (key, str(e))))
                logging.debug(self.netlogo.report(str(key)))
            if key in self.SEAWAT_uncertainties:
                setattr(self, key, value)

        #Set policy parameters if present
        if self.policy:
            for key, value in self.policy.items():
                if (key in self.NetLogo_uncertainties and key != 'name'):
                    self.netlogo.command(self.command_format.format(
                        key, value))
                elif key in self.SEAWAT_uncertainties:
                    setattr(self, key, value)
            logging.info('Policy parameters set successfully')

        #Update NetLogo globals from input parameters
        for var in nl_update_globals:
            self.netlogo.command(
                self.command_format.format(var, getattr(self, var)))

        #Run the NetLogo setup routine, creating the agents
        #Create lists of Python objects based on the NetLogo agents
        self.netlogo.command('init-agents')
        sys_obj_list = update_runtime_objectlist(self.netlogo, [],
                                                 nl_read_sys_attribs,
                                                 breed='system',
                                                 objclass=PySystem)
        well_obj_list, newgrid_flag = update_runtime_objectlist(
            self.netlogo, [],
            nl_read_well_attribs,
            breed='well',
            objclass=PyWell)

        #Assign values for uncertain NetLogo parameters
        logging.info('NetLogo parameters set successfully')

        #self.netlogo.command('init-agents')

        #Calculate geohydrological parameters linked to variable inputs
        rho_b = self.rho_solid * (1 - self.PEFF)
        kT_b = self.kT_s * (1 - self.PEFF) + self.kT_f * self.PEFF
        dmcoef = kT_b / (self.PEFF * self.rho_f * self.Cp_f) * 24 * 3600
        trpt = self.al * self.trp_mult
        trpv = trpt

        #Initialize PyGrid object
        itype = mt3.Mt3dSsm.itype_dict()
        grid_obj = PyGrid()
        grid_obj.make_grid(well_obj_list,
                           dmin=self.dmin,
                           dmax=self.dmax,
                           dz=self.dz,
                           ztop=self.ztop,
                           zbot=self.zbot,
                           nstep=self.nstep,
                           grid_extents=self.grid_extents)

        #Initial arrays for grid values (temperature, head) - for this case, assumes no groundwater flow
        #and uniform temperature
        grid_obj.ncol = len(grid_obj.XGR) - 1
        grid_obj.delr = np.diff(grid_obj.XGR)
        grid_obj.nrow = len(grid_obj.YGR) - 1
        grid_obj.delc = -np.diff(grid_obj.YGR)

        grid_obj.top = self.ztop * np.ones([grid_obj.nrow, grid_obj.ncol])
        botm_range = np.arange(self.zbot, self.ztop, self.dz)[::-1]
        botm_2d = np.ones([grid_obj.nrow, grid_obj.ncol])
        grid_obj.botm = botm_2d * botm_range[:, None, None]
        grid_obj.nlay = len(botm_range)

        grid_obj.IBOUND, grid_obj.ICBUND = boundaries(
            grid_obj)  #Create grid boundaries

        #Initial arrays for grid values (temperature, head)
        init_grid = np.ones((grid_obj.nlay, grid_obj.nrow, grid_obj.ncol))
        grid_obj.temp = 10. * init_grid

        grid_obj.HK = self.HK * init_grid
        grid_obj.VK = self.VK * init_grid

        #Set initial heads according to groundwater flow (based on mfLab Utrecht model)
        y_array = np.array([(grid_obj.YGR[:-1] - np.mean(grid_obj.YGR[:-1])) *
                            self.PEFF * -self.gwflow_y / 365 / self.HK])
        y_tile = np.array([np.tile(y_array.T, (1, grid_obj.ncol))])
        x_array = (grid_obj.XGR[:-1] - np.mean(
            grid_obj.XGR[:-1])) * self.PEFF * -self.gwflow_x / 365 / self.HK
        y_tile += x_array
        grid_obj.head = np.tile(y_tile, (grid_obj.nlay, 1, 1))

        #Set times at which to read SEAWAT output for each simulation period
        timprs = np.array([self.perlen])
        nprs = len(timprs)
        logging.info('SEAWAT parameters set successfully')

        #Iterate the coupled model
        for period in range(self.run_length):

            #Set up the text output from NetLogo
            commands = []
            self.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)
                self.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_out = ' '.join(commands)
            self.netlogo.command(c_out)

            logging.info(' -- Simulating period {0} of {1}'.format(
                period, self.run_length))
            #Run the NetLogo model for one tick
            self.netlogo.command('go')
            logging.debug('NetLogo step completed')

            #Create placeholder well list - required for MODFLOW WEL package if no wells active in NetLogo
            well_LRCQ_list = {}
            well_LRCQ_list[0] = [[0, 0, 0, 0]]
            ssm_data = {}
            ssm_data[0] = [[0, 0, 0, 0, itype['WEL']]]

            #Check the well agents which are active in NetLogo, and update the Python objects if required
            #The newgrid_flag indicates whether or not the grid should be recalculated to account for changes
            #in the list of active wells
            if well_obj_list:
                well_obj_list, newgrid_flag = update_runtime_objectlist(
                    self.netlogo, well_obj_list, nl_read_well_attribs)

            if well_obj_list and newgrid_flag:
                #If the list of active wells has changed and if there are active wells, create a new grid object
                newgrid_obj = PyGrid()
                newgrid_obj.make_grid(well_obj_list,
                                      dmin=self.dmin,
                                      dmax=self.dmax,
                                      dz=self.dz,
                                      ztop=self.ztop,
                                      zbot=self.zbot,
                                      nstep=self.nstep,
                                      grid_extents=self.grid_extents)
                #Interpolate the temperature and head arrays to match the new grid
                newgrid_obj.temp = grid_interpolate(grid_obj.temp[0, :, :],
                                                    grid_obj, newgrid_obj)
                newgrid_obj.head = grid_interpolate(grid_obj.head[0, :, :],
                                                    grid_obj, newgrid_obj)
                #Use the new simulation grid
                grid_obj = newgrid_obj

            logging.debug('Python update completed')

            if well_obj_list:
                for i in well_obj_list:
                    #Read well flows from NetLogo and locate each well in the simulation grid
                    i.Q = read_NetLogo_attrib(self.netlogo, 'Q', i.who)
                    i.calc_LRC(grid_obj)
                #Create well and temperature lists following MODFLOW/MT3DMS format
                well_LRCQ_list = create_LRCQ_list(well_obj_list, grid_obj)
                ssm_data = create_conc_list(well_obj_list)

            #Initialize MODFLOW packages using FloPy
            #ml = mf.Modflow(self.name, version='mf2005', exe_name=self.swtexe_name, model_ws=self.dirs[0])
            swtm = swt.Seawat(self.name,
                              exe_name=self.swtexe_name,
                              model_ws=self.dirs[0])
            discret = mf.ModflowDis(swtm,
                                    nrow=grid_obj.nrow,
                                    ncol=grid_obj.ncol,
                                    nlay=grid_obj.nlay,
                                    delr=grid_obj.delr,
                                    delc=grid_obj.delc,
                                    laycbd=0,
                                    top=self.ztop,
                                    botm=self.zbot,
                                    nper=self.nper,
                                    perlen=self.perlen,
                                    nstp=self.nstp,
                                    steady=self.steady)

            bas = mf.ModflowBas(swtm,
                                ibound=grid_obj.IBOUND,
                                strt=grid_obj.head)
            lpf = mf.ModflowLpf(swtm,
                                hk=self.HK,
                                vka=self.VK,
                                ss=0.0,
                                sy=0.0,
                                laytyp=0,
                                layavg=0)

            wel = mf.ModflowWel(swtm, stress_period_data=well_LRCQ_list)

            words = ['head', 'drawdown', 'budget', 'phead', 'pbudget']
            save_head_every = 1
            oc = mf.ModflowOc(swtm)
            pcg = mf.ModflowPcg(swtm,
                                mxiter=200,
                                iter1=200,
                                npcond=1,
                                hclose=0.001,
                                rclose=0.001,
                                relax=1.0,
                                nbpol=0)
            #ml.write_input()

            #Initialize MT3DMS packages
            #mt = mt3.Mt3dms(self.name, 'nam_mt3dms', modflowmodel=ml, model_ws=self.dirs[0])
            adv = mt3.Mt3dAdv(
                swtm,
                mixelm=0,  #-1 is TVD
                percel=1,
                nadvfd=1,
                #Particle based methods
                nplane=0,
                mxpart=250000,
                itrack=3,
                dceps=1e-4,
                npl=5,
                nph=8,
                npmin=1,
                npmax=16)
            btn = mt3.Mt3dBtn(swtm,
                              cinact=-100.,
                              icbund=grid_obj.ICBUND,
                              prsity=self.PEFF,
                              sconc=[grid_obj.temp][0],
                              ifmtcn=-1,
                              chkmas=False,
                              nprobs=0,
                              nprmas=1,
                              dt0=0.0,
                              ttsmult=1.5,
                              ttsmax=20000.,
                              ncomp=1,
                              nprs=nprs,
                              timprs=timprs,
                              mxstrn=9999)
            dsp = mt3.Mt3dDsp(swtm,
                              al=self.al,
                              trpt=trpt,
                              trpv=trpv,
                              dmcoef=dmcoef)
            rct = mt3.Mt3dRct(swtm, isothm=0, ireact=0, igetsc=0, rhob=rho_b)
            gcg = mt3.Mt3dGcg(swtm,
                              mxiter=50,
                              iter1=50,
                              isolve=1,
                              cclose=1e-3,
                              iprgcg=0)
            ssm = mt3.Mt3dSsm(swtm, stress_period_data=ssm_data)
            #mt.write_input()

            #Initialize SEAWAT packages
            # mswtf = swt.Seawat(self.name, 'nam_swt', modflowmodel=ml, mt3dmsmodel=mt,
            #                    model_ws=self.dirs[0])
            swtm.write_input()

            #Run SEAWAT
            #m = mswtf.run_model(silent=True)
            m = swtm.run_model(silent=True)
            logging.debug('SEAWAT step completed')

            #Copy Modflow/MT3DMS output to new files
            shutil.copyfile(
                os.path.join(self.dirs[0], self.name + '.hds'),
                os.path.join(self.dirs[0], self.name + str(period) + '.hds'))
            shutil.copyfile(
                os.path.join(self.dirs[0], 'MT3D001.UCN'),
                os.path.join(self.dirs[0], self.name + str(period) + '.UCN'))

            #Create head file object and read head array for next simulation period
            h_obj = bf.HeadFile(
                os.path.join(self.dirs[0], self.name + str(period) + '.hds'))
            grid_obj.head = h_obj.get_data(totim=self.perlen)

            #Create concentration file object and read temperature array for next simulation period
            t_obj = bf.UcnFile(
                os.path.join(self.dirs[0], self.name + str(period) + '.UCN'))
            grid_obj.temp = t_obj.get_data(totim=self.perlen)

            logging.debug('Output processed')

            if well_obj_list:
                for i in well_obj_list:
                    #Update each active Python well object with the temperature and head at its grid location
                    i.T_modflow = grid_obj.temp[i.L[0], i.R, i.C]
                    i.H_modflow = grid_obj.head[i.L[0], i.R, i.C]
                #Update the NetLogo agents from the corresponding Python objects
                write_NetLogo_attriblist(self.netlogo, well_obj_list,
                                         nl_update_well_attribs)

            #As an example of data exchange, we can calculate the fraction of the simulated grid in which
            #the temperature change is significant, and send this value to a NetLogo global variable
            use = subsurface_use(grid_obj, grid_obj.temp)

            write_NetLogo_global(self.netlogo, 'SubsurfaceUse', use)

            logging.debug('NetLogo update completed')

            h_obj.file.close()
            t_obj.file.close()

        self.netlogo.command('file-close-all')
        self._handle_outcomes()