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
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