import numpy as np
from scipy import pi
from ..Contour import Contour
from ..Paths import ComplexLine, ComplexArc
from .AnnulusSector import AnnulusSector
[docs]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