cxroots.contours.Annulus — cxroots 1.1.0 documentation

# Source code for cxroots.contours.Annulus

    import numpy as np
    from scipy import pi

    from ..Contour import Contour
    from ..Paths import ComplexLine, ComplexArc
    from .AnnulusSector import AnnulusSector

    class Annulus(Contour):
    	"""
    	An annulus in the complex plane with the outer circle positively oriented
    	and the inner circle negatively oriented.

    	Parameters
    	----------
    	center : complex
    		The center of the annulus in the complex plane.
    	radii : tuple
    		A tuple of length two of the form (inner_radius, outer_radius).

    	Examples
    	--------
    	.. plot::
    		:include-source:

    		from cxroots import Annulus
    		annulus = Annulus(center=0, radii=(0.5,0.75))
    		annulus.show()
    	"""
    	def __init__(self, center, radii):
    		self.center = center
    		self.radii = radii
    		self.axisName = ('r', 'phi')

    		segments = [ComplexArc(center, radii[1], 0, 2*pi), ComplexArc(center, radii[0], 0, -2*pi)]
    		super(Annulus, self).__init__(segments)

    	def __str__(self):
    		return 'Annulus: center={center.real:.3f}{center.imag:+.3f}i, inner radius={radii[0]:.3f}, outer radius={radii[1]:.3f}'.format(center=self.center, radii=self.radii)

    	@property
    	def centralPoint(self):
    		# get the central point within the contour
    		r = (self.radii[0] + self.radii[1])/2
    		return r

    	@property
    	def area(self):
    		return pi*(self.radii[1]**2 - self.radii[0]**2)

    	def contains(self, z):
    		""" Returns True if the point z lies within the contour, False if otherwise """
    		return self.radii[0] < abs(z - self.center) < self.radii[1]

    	def subdivide(self, axis, divisionFactor=0.5):
    		"""
    		Subdivide the contour

    		Parameters
    		----------
    		axis : str, can be either 'r' or 'phi'
    			The axis along which the line subdividing the contour is a constant.
    		divisionFactor : float in range (0,1), optional
    			Determines the point along 'axis' at which the line dividing the box is placed

    		Returns
    		-------
    		boxes : list of contours
    			Two annuluses if axis is 'r'.
    			Two half-annuluses oriented according to divisionFactor if axis is 'phi'.
    		"""
    		if axis == 'r' or self.axisName[axis] == 'r':
    			midpoint = self.radii[0] + divisionFactor*(self.radii[1]-self.radii[0])
    			box1 = Annulus(self.center, [self.radii[0], midpoint])
    			box2 = Annulus(self.center, [midpoint, self.radii[1]])

    			box1.segments[1] = self.segments[1]
    			box2.segments[0] = self.segments[0]
    			box1.segments[0]._reversePath = box2.segments[1]
    			box2.segments[1]._reversePath = box1.segments[0]

    			box1._createdBySubdivisionAxis = axis
    			box2._createdBySubdivisionAxis = axis

    		elif axis == 'phi' or self.axisName[axis] == 'phi':
    			# Subdividing into two radial boxes rather than one to
    			# ensure that an error is raised if one of the new paths
    			# is too close to a root
    			# XXX: introduce another parameter for phi1

    			phi0 = 2*pi*divisionFactor
    			phi1 = phi0 + pi

    			box1 = AnnulusSector(self.center, self.radii, [phi0, phi1])
    			box2 = AnnulusSector(self.center, self.radii, [phi1, phi0])

    			box1.segments[0]._reversePath = box2.segments[2]
    			box2.segments[2]._reversePath = box1.segments[0]
    			box1.segments[2]._reversePath = box2.segments[0]
    			box2.segments[0]._reversePath = box1.segments[2]

    		for box in [box1, box2]:
    			box._createdBySubdivisionAxis = axis
    			box._parentBox = self
    		self._childBoxes = [box1, box2]

    		return box1, box2

    	def randomPoint(self):
    		""" Returns a random point inside the Annulus """
    		r   = np.random.uniform(*self.radii)
    		phi = np.random.uniform(0,2*pi)
    		return r*exp(1j*phi) + self.center