# Source code for openmdao.lib.datatypes.domain.vector

```from math import atan2, cos, hypot, radians, sin

import numpy

[docs]class Vector(object):
"""
Vector data for a :class:`FlowSolution`.
In Cartesian coordinates, array indexing order is x,y,z;
so an 'i-face' is a y,z surface.
In cylindrical coordinates, array indexing order is z,r,t;
so an 'i-face' is an r,t surface.
"""

def __init__(self):
self.x = None
self.y = None
self.z = None
self.r = None
self.t = None

@property
[docs]    def shape(self):
""" Tuple of index limits. """
for component in ('x', 'y', 'z', 'r', 't'):
arr = getattr(self, component)
if arr is not None:
return arr.shape
return ()

@property
[docs]    def extent(self):
""" Tuple of component ranges. """
if self.x is not None:
if self.y is not None:
if self.z is not None:
return (self.x.min(), self.x.max(),
self.y.min(), self.y.max(),
self.z.min(), self.z.max())
return (self.x.min(), self.x.max(),
self.y.min(), self.y.max())
return (self.x.min(), self.x.max())

elif self.r is not None and self.t is not None:
if self.z is not None:
return (self.z.min(), self.z.max(),
self.r.min(), self.r.max(),
self.t.min(), self.t.max())
return (self.r.min(), self.r.max(),
self.t.min(), self.t.max())

return ()

[docs]    def is_equivalent(self, other, name, logger, tolerance=0.):
"""
Test if self and `other` are equivalent.

other: Vector
The vector to check against.

name: string
Name of this vector, used for reporting differences.

logger: Logger or None
Used to log debug messages that will indicate what if anything is
not equivalent.

tolerance: float
The maximum relative difference in array values to be considered
equivalent.
"""
if not isinstance(other, Vector):
logger.debug('other is not a Vector object.')
return False
for component in ('x', 'y', 'z', 'r', 't'):
if not self._check_equivalent(other, name, component, logger,
tolerance):
return False
return True

def _check_equivalent(self, other, name, component, logger, tolerance):
""" Check equivalence to a component array. """
arr = getattr(self, component)
other_arr = getattr(other, component)
if arr is None:
if other_arr is not None:
logger.debug("%s has no %s component but 'other' does.", name,
component.upper())
return False
else:
if tolerance > 0.:
if not numpy.allclose(other_arr, arr, tolerance, tolerance):
logger.debug("%s %s values are not 'close'.", name,
component.upper())
return False
else:
if (other_arr != arr).any():
logger.debug('%s %s values are not equal.', name,
component.upper())
return False
return True

[docs]    def flip_z(self):
""" Convert to other-handed coordinate system. """
if self.z is None:
raise AttributeError('flip_z: no Z component')
self.z *= -1.

[docs]    def make_cartesian(self, grid, axis='z'):
"""
Convert to Cartesian coordinate system.

grid: GridCoordinates
Must be in cylindrical form.

axis: string
Specifies which is the cylinder axis ('z' or 'x').
"""
if grid.shape != self.shape:
raise NotImplementedError('make_cartesian: grid shape mismatch'
' not supported')
gt_flat = grid.t.flat
r_flat = self.r.flat
t_flat = self.t.flat

if axis == 'z':
self.x = self.r.copy()
self.y = self.r.copy()
x_flat = self.x.flat
y_flat = self.y.flat
for i in range(self.r.size):
gt = gt_flat[i]
sine = sin(gt)
cosine = cos(gt)
r = r_flat[i]
t = t_flat[i]
x_flat[i] = r*cosine - t*sine
y_flat[i] = r*sine   + t*cosine
self.r = None
self.t = None

elif axis == 'x':
self.x = self.z
self.y = self.r.copy()
self.z = self.r.copy()
y_flat = self.y.flat
z_flat = self.z.flat
for i in range(self.r.size):
gt = gt_flat[i]
sine = sin(gt)
cosine = cos(gt)
r = r_flat[i]
t = t_flat[i]
y_flat[i] = r*cosine - t*sine
z_flat[i] = r*sine   + t*cosine
self.r = None
self.t = None

else:
raise ValueError("axis must be 'z' or 'x'")

[docs]    def make_cylindrical(self, grid, axis='z'):
"""
Convert to cylindrical coordinate system.

grid: GridCoordinates
Must be in cylindrical form.

axis: string
Specifies which is the cylinder axis ('z' or 'x').
"""
if grid.shape != self.shape:
raise NotImplementedError('make_cylindrical: grid shape mismatch'
' not supported')
gt_flat = grid.t.flat
self.r = self.x.copy()
self.t = self.x.copy()
r_flat = self.r.flat
t_flat = self.t.flat

if axis == 'z':
x_flat = self.x.flat
y_flat = self.y.flat
for i in range(self.x.size):
gt = gt_flat[i]
x = x_flat[i]
y = y_flat[i]
magnitude = hypot(x, y)
rel_theta = atan2(y, x) - gt
r_flat[i] = magnitude * cos(rel_theta)
t_flat[i] = magnitude * sin(rel_theta)
self.x = None
self.y = None

elif axis == 'x':
y_flat = self.y.flat
z_flat = self.z.flat
for i in range(self.y.size):
gt = gt_flat[i]
y = y_flat[i]
z = z_flat[i]
magnitude = hypot(y, z)
rel_theta = atan2(z, y) - gt
r_flat[i] = magnitude * cos(rel_theta)
t_flat[i] = magnitude * sin(rel_theta)
self.z = self.x
self.x = None
self.y = None

else:
raise ValueError("axis must be 'z' or 'x'")

"""

deg: float (degrees)
Amount of rotation.
"""
if self.y is None:
if self.z is None:

y_new  = self.y*cosine - self.z*sine
self.z = self.z*cosine + self.y*sine
self.y = y_new

"""

deg: float (degrees)
Amount of rotation.
"""
if self.x is None:
if self.z is None:

x_new  = self.x*cosine - self.z*sine
self.z = self.z*cosine + self.x*sine
self.x = x_new

"""

deg: float (degrees)
Amount of rotation.
"""
if self.x is None: