예제 #1
0
    def set_residual(self, pores=[], overwrite=False):
        r"""
        Method to start invasion in a network w. residual saturation.
        Called after inlets are set.

        Parameters
        ----------
        pores : array_like
            The pores locations that are to be filled with invader at the
            beginning of the simulation.

        overwrite : boolean
            If ``True`` then all existing inlet locations will be removed and
            then the supplied locations will be added.  If ``False``, then
            supplied locations are added to any already existing locations.

        Notes
        -----
        Currently works for pores only and treats inner throats, i.e.
        those that connect two pores in the cluster as invaded and outer ones
        as uninvaded. Uninvaded throats are added to a new residual cluster
        queue but do not start invading independently if not connected to an
        inlet.

        Step 1. Identify clusters in the phase occupancy.
        Step 2. Look for clusters that are connected or contain an inlet
        Step 3. For those that are merge into inlet cluster. May be connected
        to more than one - run should sort this out
        Step 4. For those that are isolated set the queue to not invading.
        Step 5. (in run) When isolated cluster is met my invading cluster it
        merges in and starts invading


        """
        Ps = self._parse_indices(pores)
        if overwrite:
            self['pore.residual'] = False
        self['pore.residual'][Ps] = True
        residual = self['pore.residual']
        net = self.project.network
        conns = net['throat.conns']
        rclusters = site_percolation(conns, residual).sites
        rcluster_ids = np.unique(rclusters[rclusters > -1])
        initial_num = len(self.queue)-1
        for rcluster_id in rcluster_ids:
            rPs = rclusters == rcluster_id
            existing = np.unique(self['pore.cluster'][rPs])
            existing = existing[existing > -1]
            if len(existing) > 0:
                # There was at least one inlet cluster connected to this
                # residual cluster, pick the first one.
                cluster_num = existing[0]
            else:
                # Make a new cluster queue
                cluster_num = len(self.queue)
                self.queue.append([])
            queue = self.queue[cluster_num]
            # Set the residual pores and inner throats as part of cluster
            self['pore.cluster'][rPs] = cluster_num
            Ts = net.find_neighbor_throats(pores=rPs,
                                           flatten=True,
                                           mode='xnor')
            self['throat.cluster'][Ts] = cluster_num
            self['pore.invasion_sequence'][rPs] = 0
            self['throat.invasion_sequence'][Ts] = 0
            self['pore.invasion_pressure'][rPs] = -np.inf
            self['throat.invasion_pressure'][Ts] = -np.inf
            # Add all the outer throats to the queue
            Ts = net.find_neighbor_throats(pores=rPs,
                                           flatten=True,
                                           mode='exclusive_or')
            for T in Ts:
                data = []
                # Pc
                data.append(self['throat.entry_pressure'][T])
                # Element Index
                data.append(T)
                # Element Type (Pore of Throat)
                data.append('throat')
                hq.heappush(queue, data)
        self.invasion_running = [True]*len(self.queue)
        # we have added new clusters that are currently isolated and we
        # need to stop them invading until they merge into an invading
        # cluster
        for c_num in range(len(self.queue)):
            if c_num > initial_num:
                self.invasion_running[c_num] = False
예제 #2
0
    def set_residual(self, pores=[], overwrite=False):
        r"""
        Method to start invasion in a network w. residual saturation.
        Called after inlets are set.

        Parameters
        ----------
        pores : array_like
            The pores locations that are to be filled with invader at the
            beginning of the simulation.

        overwrite : boolean
            If ``True`` then all existing inlet locations will be removed and
            then the supplied locations will be added.  If ``False``, then
            supplied locations are added to any already existing locations.

        Notes
        -----
        Currently works for pores only and treats inner throats, i.e.
        those that connect two pores in the cluster as invaded and outer ones
        as uninvaded. Uninvaded throats are added to a new residual cluster
        queue but do not start invading independently if not connected to an
        inlet.

        Step 1. Identify clusters in the phase occupancy.
        Step 2. Look for clusters that are connected or contain an inlet
        Step 3. For those that are merge into inlet cluster. May be connected
        to more than one - run should sort this out
        Step 4. For those that are isolated set the queue to not invading.
        Step 5. (in run) When isolated cluster is met my invading cluster it
        merges in and starts invading


        """
        Ps = self._parse_indices(pores)
        if overwrite:
            self['pore.residual'] = False
        self['pore.residual'][Ps] = True
        residual = self['pore.residual']
        net = self.project.network
        conns = net['throat.conns']
        rclusters = site_percolation(conns, residual).sites
        rcluster_ids = np.unique(rclusters[rclusters > -1])
        initial_num = len(self.queue)-1
        for rcluster_id in rcluster_ids:
            rPs = rclusters == rcluster_id
            existing = np.unique(self['pore.cluster'][rPs])
            existing = existing[existing > -1]
            if len(existing) > 0:
                # There was at least one inlet cluster connected to this
                # residual cluster, pick the first one.
                cluster_num = existing[0]
            else:
                # Make a new cluster queue
                cluster_num = len(self.queue)
                self.queue.append([])
            queue = self.queue[cluster_num]
            # Set the residual pores and inner throats as part of cluster
            self['pore.cluster'][rPs] = cluster_num
            Ts = net.find_neighbor_throats(pores=rPs,
                                           flatten=True,
                                           mode='xnor')
            self['throat.cluster'][Ts] = cluster_num
            self['pore.invasion_sequence'][rPs] = 0
            self['throat.invasion_sequence'][Ts] = 0
            self['pore.invasion_pressure'][rPs] = -np.inf
            self['throat.invasion_pressure'][Ts] = -np.inf
            # Add all the outer throats to the queue
            Ts = net.find_neighbor_throats(pores=rPs,
                                           flatten=True,
                                           mode='exclusive_or')
            for T in Ts:
                data = []
                # Pc
                data.append(self['throat.entry_pressure'][T])
                # Element Index
                data.append(T)
                # Element Type (Pore of Throat)
                data.append('throat')
                hq.heappush(queue, data)
        self.invasion_running = [True]*len(self.queue)
        # we have added new clusters that are currently isolated and we
        # need to stop them invading until they merge into an invading
        # cluster
        for c_num in range(len(self.queue)):
            if c_num > initial_num:
                self.invasion_running[c_num] = False
예제 #3
0
    def run(self, points=25, start=None, stop=None):
        r"""
        Runs the percolation algorithm to determine which pores and throats
        will be invaded at each given pressure point.

        Parameters
        ----------
        points: int or array_like
            An array containing the pressure points to apply.  If a scalar is
            given then an array will be generated with the given number of
            points spaced between the lowest and highest values of
            throat entry pressures using logarithmic spacing.  To specify low
            and high pressure points use the ``start`` and ``stop`` arguments.
        start : int
            The optional starting point to use when generating pressure points.
            If not given the half the lowest capillary entry pressure in the
            network is used.
        stop : int
            The optional stopping point to use when generating pressure points.
            If not given, then twice the highest capillary entry pressure in
            the network is used.

        Notes
        -----
        The inlet sites are set to invaded to start the simulation.  This means
        that if 'internal' pores are used as inlets the capillary pressure
        curve will begin at a non-zero invading phase saturation.  To avoid
        this either set the inlet pore volumes to zero or add boundary pores
        to the inlet face, and set their volumes to zero.

        """
        phase = self.project[self.settings.phase]
        # Parse inputs and generate list of invasion points if necessary
        if self.settings['mode'] == 'bond':
            self['throat.entry_pressure'] = \
                phase[self.settings['throat_entry_threshold']]
            if start is None:
                start = np.amin(self['throat.entry_pressure'])*0.5
            if stop is None:
                stop = np.amax(self['throat.entry_pressure'])*2.0

        elif self.settings['mode'] == 'site':
            self['pore.entry_pressure'] = \
                phase[self.settings['pore_entry_threshold']]
            if start is None:
                start = np.amin(self['pore.entry_pressure'])*0.5
            if stop is None:
                stop = np.amax(self['pore.entry_pressure'])*2.0
        else:
            raise Exception('Percolation type has not been set')
        if isinstance(points, int):
            points = np.logspace(start=np.log10(max(1, start)),
                                 stop=np.log10(stop), num=points)
        self._points = points

        # Ensure pore inlets have been set IF access limitations is True
        if self.settings['access_limited']:
            if np.sum(self['pore.inlets']) == 0:
                raise Exception('Inlet pores must be specified first')
            else:
                Pin = self['pore.inlets']

        # Generate curve from points
        conns = self.project.network['throat.conns']
        for inv_val in points:
            if self.settings['mode'] == 'bond':
                t_invaded = self['throat.entry_pressure'] <= inv_val
                labels = bond_percolation(conns, t_invaded)
            elif self.settings['mode'] == 'site':
                p_invaded = self['pore.entry_pressure'] <= inv_val
                labels = site_percolation(conns, p_invaded)

            # Optionally remove clusters not connected to the inlets
            if self.settings['access_limited']:
                labels = remove_isolated_clusters(labels=labels,
                                                  inlets=Pin)

            # Store current applied pressure in newly invaded pores
            pinds = (self['pore.invasion_pressure'] == np.inf) * \
                    (labels.sites >= 0)
            self['pore.invasion_pressure'][pinds] = inv_val
            # Store current applied pressure in newly invaded throats
            tinds = (self['throat.invasion_pressure'] == np.inf) * \
                    (labels.bonds >= 0)
            self['throat.invasion_pressure'][tinds] = inv_val

        # Convert invasion pressures in sequence values
        Pinv = self['pore.invasion_pressure']
        Tinv = self['throat.invasion_pressure']
        Pseq = np.searchsorted(np.unique(Pinv), Pinv)
        Tseq = np.searchsorted(np.unique(Tinv), Tinv)
        self['pore.invasion_sequence'] = Pseq
        self['throat.invasion_sequence'] = Tseq
예제 #4
0
    def run(self, points=25, start=None, stop=None):
        r"""
        Runs the percolation algorithm to determine which pores and throats
        will be invaded at each given pressure point.

        Parameters
        ----------
        points: int or array_like
            An array containing the pressure points to apply.  If a scalar is
            given then an array will be generated with the given number of
            points spaced between the lowest and highest values of
            throat entry pressures using logarithmic spacing.  To specify low
            and high pressure points use the ``start`` and ``stop`` arguments.

        start : int
            The optional starting point to use when generating pressure points.
            If not given the half the lowest capillary entry pressure in the
            network is used.

        stop : int
            The optional stopping point to use when generating pressure points.
            If not given, then twice the highest capillary entry pressure in
            the network is used.

        Note
        ----
        The inlet sites are set to invaded to start the simulation.  This means
        that if 'internal' pores are used as inlets the capillary pressure
        curve will begin at a non-zero invading phase saturation.  To avoid
        this either set the inlet pore volumes to zero or add boundary pores
        to the inlet face, and set their volumes to zero.

        """
        phase = self.project.find_phase(self)
        # Parse inputs and generate list of invasion points if necessary
        if self.settings['mode'] == 'bond':
            self['throat.entry_pressure'] = \
                phase[self.settings['throat_entry_threshold']]
            if start is None:
                start = sp.amin(self['throat.entry_pressure'])*0.5
            if stop is None:
                stop = sp.amax(self['throat.entry_pressure'])*2.0

        elif self.settings['mode'] == 'site':
            self['pore.entry_pressure'] = \
                phase[self.settings['pore_entry_threshold']]
            if start is None:
                start = sp.amin(self['pore.entry_pressure'])*0.5
            if stop is None:
                stop = sp.amax(self['pore.entry_pressure'])*2.0
        else:
            raise Exception('Percolation type has not been set')
        if type(points) is int:
            points = sp.logspace(start=sp.log10(max(1, start)),
                                 stop=sp.log10(stop), num=points)
        self._points = points

        # Ensure pore inlets have been set IF access limitations is True
        if self.settings['access_limited']:
            if sp.sum(self['pore.inlets']) == 0:
                raise Exception('Inlet pores must be specified first')
            else:
                Pin = self['pore.inlets']

        # Generate curve from points
        conns = self.project.network['throat.conns']
        for inv_val in points:
            if self.settings['mode'] == 'bond':
                t_invaded = self['throat.entry_pressure'] <= inv_val
                labels = bond_percolation(conns, t_invaded)
            elif self.settings['mode'] == 'site':
                p_invaded = self['pore.entry_pressure'] <= inv_val
                labels = site_percolation(conns, p_invaded)

            # Optionally remove clusters not connected to the inlets
            if self.settings['access_limited']:
                labels = remove_isolated_clusters(labels=labels,
                                                  inlets=Pin)

            # Store current applied pressure in newly invaded pores
            pinds = (self['pore.invasion_pressure'] == sp.inf) * \
                    (labels.sites >= 0)
            self['pore.invasion_pressure'][pinds] = inv_val
            # Store current applied pressure in newly invaded throats
            tinds = (self['throat.invasion_pressure'] == sp.inf) * \
                    (labels.bonds >= 0)
            self['throat.invasion_pressure'][tinds] = inv_val

        # Convert invasion pressures in sequence values
        Pinv = self['pore.invasion_pressure']
        Tinv = self['throat.invasion_pressure']
        Pseq = sp.searchsorted(sp.unique(Pinv), Pinv)
        Tseq = sp.searchsorted(sp.unique(Tinv), Tinv)
        self['pore.invasion_sequence'] = Pseq
        self['throat.invasion_sequence'] = Tseq