Source code for wisdem.commonse.csystem

#!/usr/bin/env python
# encoding: utf-8
"""
csystem.py

Created by Andrew Ning on 2/21/2012.
Copyright (c) NREL. All rights reserved.
"""

from __future__ import print_function

import numpy as np


[docs] class DirectionVector(object): """Handles rotation of direction vectors to appropriate coordinate systems. All angles must be in degrees. """ def __init__(self, x, y, z, dx=None, dy=None, dz=None): """3-Dimensional vector that depends on direction only (not position). Parameters ---------- x : float or ndarray x-direction of vector(s) y : float or ndarray y-direction of vector(s) z : float or ndarray z-direction of vector(s) """ self.x = np.array(x) self.y = np.array(y) self.z = np.array(z) if dx is None: dx = {} dx["dx"] = np.ones_like(self.x) dx["dy"] = np.zeros_like(self.y) dx["dz"] = np.zeros_like(self.z) dy = {} dy["dx"] = np.zeros_like(self.x) dy["dy"] = np.ones_like(self.y) dy["dz"] = np.zeros_like(self.z) dz = {} dz["dx"] = np.zeros_like(self.x) dz["dy"] = np.zeros_like(self.y) dz["dz"] = np.ones_like(self.z) self.dx = dx self.dy = dy self.dz = dz @classmethod def fromArray(cls, array): """initialize with NumPy array Parameters ---------- array : ndarray construct DirectionVector using array of size 3 """ return cls(array[0], array[1], array[2]) def toArray(self): """convert DirectionVector to NumPy array Returns ------- array : ndarray NumPy array in order x, y, z containing DirectionVector data """ return np.c_[self.x, self.y, self.z] def _rotateAboutZ(self, xstring, ystring, zstring, theta, thetaname, reverse=False): """ x X y = z. rotate c.s. about z, +theta all angles in degrees """ thetaM = 1.0 if reverse: thetaM = -1.0 x = getattr(self, xstring) y = getattr(self, ystring) z = getattr(self, zstring) dx = getattr(self, "d" + xstring) dy = getattr(self, "d" + ystring) dz = getattr(self, "d" + zstring) theta = np.radians(theta * thetaM) c = np.cos(theta) s = np.sin(theta) xnew = x * c + y * s ynew = -x * s + y * c znew = z angles = [] for key in dx.keys(): if not key in ["dx", "dy", "dz"]: angles.append(key) dxnew = {} dxnew["dx"] = dx["dx"] * c + dy["dx"] * s dxnew["dy"] = dx["dy"] * c + dy["dy"] * s dxnew["dz"] = dx["dz"] * c + dy["dz"] * s dxnew["d" + thetaname] = (-x * s + y * c) * np.radians(thetaM) for dangle in angles: dxnew[dangle] = dx[dangle] * c + dy[dangle] * s dynew = {} dynew["dx"] = -dx["dx"] * s + dy["dx"] * c dynew["dy"] = -dx["dy"] * s + dy["dy"] * c dynew["dz"] = -dx["dz"] * s + dy["dz"] * c dynew["d" + thetaname] = (-x * c - y * s) * np.radians(thetaM) for dangle in angles: dynew[dangle] = -dx[dangle] * s + dy[dangle] * c dznew = {} dznew["dx"] = dz["dx"] * np.ones_like(theta) # multiply by ones just to get right size in case of float dznew["dy"] = dz["dy"] * np.ones_like(theta) dznew["dz"] = dz["dz"] * np.ones_like(theta) dznew["d" + thetaname] = np.zeros_like(theta) for dangle in angles: dznew[dangle] = dz[dangle] return xnew, ynew, znew, dxnew, dynew, dznew
[docs] def windToInertial(self, beta): """Rotates from wind-aligned to inertial Parameters ---------- beta : float (deg) wind angle Returns ------- vector : DirectionVector a DirectionVector in the inertial coordinate system """ xw, yw, zw, dxw, dyw, dzw = self._rotateAboutZ("x", "y", "z", beta, "beta", reverse=True) return DirectionVector(xw, yw, zw, dxw, dyw, dzw)
[docs] def inertialToWind(self, beta): """Rotates from inertial to wind-aligned Parameters ---------- beta : float (deg) wind angle Returns ------- vector : DirectionVector a DirectionVector in the wind-aligned coordinate system """ xw, yw, zw, dxw, dyw, dzw = self._rotateAboutZ("x", "y", "z", beta, "beta") return DirectionVector(xw, yw, zw, dxw, dyw, dzw)
[docs] def yawToWind(self, Psi): """Rotates from yaw-aligned to wind-aligned Parameters ---------- Psi : float (deg) yaw angle Returns ------- vector : DirectionVector a DirectionVector in the wind-aligned coordinate system """ xw, yw, zw, dxw, dyw, dzw = self._rotateAboutZ("x", "y", "z", Psi, "yaw", reverse=True) return DirectionVector(xw, yw, zw, dxw, dyw, dzw)
[docs] def windToYaw(self, Psi): """Rotates from wind-aligned to yaw-aligned Parameters ---------- Psi : float (deg) yaw angle Returns ------- vector : DirectionVector a DirectionVector in the yaw-aligned coordinate system """ xy, yy, zy, dxy, dyy, dzy = self._rotateAboutZ("x", "y", "z", Psi, "yaw") return DirectionVector(xy, yy, zy, dxy, dyy, dzy)
[docs] def hubToYaw(self, Theta, derivatives=False): """Rotates from hub-aligned to yaw-aligned Parameters ---------- Theta : float (deg) tilt angle Returns ------- vector : DirectionVector a DirectionVector in the yaw-aligned coordinate system """ zy, xy, yy, dzy, dxy, dyy = self._rotateAboutZ("z", "x", "y", Theta, "tilt", reverse=True) return DirectionVector(xy, yy, zy, dxy, dyy, dzy)
[docs] def yawToHub(self, Theta): """Rotates from yaw-aligned to hub-aligned Parameters ---------- Theta : float (deg) tilt angle Returns ------- vector : DirectionVector a DirectionVector in the hub-aligned coordinate system """ zh, xh, yh, dzh, dxh, dyh = self._rotateAboutZ("z", "x", "y", Theta, "tilt") return DirectionVector(xh, yh, zh, dxh, dyh, dzh)
[docs] def hubToAzimuth(self, Lambda): """Rotates from hub-aligned to azimuth-aligned Parameters ---------- Lambda : float or ndarray (deg) azimuth angle Returns ------- vector : DirectionVector a DirectionVector in the azimuth-aligned coordinate system """ yz, zz, xz, dyz, dzz, dxz = self._rotateAboutZ("y", "z", "x", Lambda, "azimuth") return DirectionVector(xz, yz, zz, dxz, dyz, dzz)
[docs] def azimuthToHub(self, Lambda): """Rotates from azimuth-aligned to hub-aligned Parameters ---------- Lambda : float or ndarray (deg) azimuth angle Returns ------- vector : DirectionVector a DirectionVector in the hub-aligned coordinate system """ yh, zh, xh, dyh, dzh, dxh = self._rotateAboutZ("y", "z", "x", Lambda, "azimuth", reverse=True) return DirectionVector(xh, yh, zh, dxh, dyh, dzh)
[docs] def azimuthToBlade(self, Phi): """Rotates from azimuth-aligned to blade-aligned Parameters ---------- Phi : float (deg) precone angle Returns ------- vector : DirectionVector a DirectionVector in the blade-aligned coordinate system """ zb, xb, yb, dzb, dxb, dyb = self._rotateAboutZ("z", "x", "y", Phi, "precone", reverse=True) return DirectionVector(xb, yb, zb, dxb, dyb, dzb)
[docs] def bladeToAzimuth(self, Phi): """Rotates from blade-aligned to azimuth-aligned Parameters ---------- Phi : float (deg) precone angle Returns ------- vector : DirectionVector a DirectionVector in the azimuth-aligned coordinate system """ za, xa, ya, dza, dxa, dya = self._rotateAboutZ("z", "x", "y", Phi, "precone") return DirectionVector(xa, ya, za, dxa, dya, dza)
[docs] def airfoilToBlade(self, theta): """Rotates from airfoil-aligned to blade-aligned Parameters ---------- theta : float (deg) twist angle Returns ------- vector : DirectionVector a DirectionVector in the blade-aligned coordinate system """ xb, yb, zb, dxb, dyb, dzb = self._rotateAboutZ("x", "y", "z", theta, "theta") return DirectionVector(xb, yb, zb, dxb, dyb, dzb)
[docs] def bladeToAirfoil(self, theta): """Rotates from blade-aligned to airfoil-aligned Parameters ---------- theta : float (deg) twist angle Returns ------- vector : DirectionVector a DirectionVector in the airfoil-aligned coordinate system """ xa, ya, za, dxa, dya, dza = self._rotateAboutZ("x", "y", "z", theta, "theta", reverse=True) return DirectionVector(xa, ya, za, dxa, dya, dza)
[docs] def airfoilToProfile(self): """Rotates from airfoil-aligned to profile Returns ------- vector : DirectionVector a DirectionVector in the profile coordinate system """ return DirectionVector(self.y, self.x, self.z, self.dy, self.dx, self.dz)
[docs] def profileToAirfoil(self): """Rotates from profile to airfoil-aligned Returns ------- vector : DirectionVector a DirectionVector in the airfoil-aligned coordinate system """ return DirectionVector(self.y, self.x, self.z, self.dy, self.dx, self.dz)
def cross(self, other): """cross product between two DirectionVectors Parameters ---------- other : DirectionVector other vector to cross with Returns ------- vector : DirectionVector vector = self X other """ v1 = np.c_[self.x, self.y, self.z] v2 = np.c_[other.x, other.y, other.z] v = np.cross(v1, v2) if len(v.shape) > 1: return DirectionVector(v[:, 0], v[:, 1], v[:, 2]) else: return DirectionVector(v[0], v[1], v[2]) def cross_deriv(self, other, namea="a", nameb="b"): """defined only for floats for now""" # c = a X b a = self b = other dx = {} dx[namea] = np.r_[0.0, b.z, -b.y] dx[nameb] = np.r_[0.0, -a.z, a.y] dy = {} dy[namea] = np.r_[-b.z, 0.0, b.x] dy[nameb] = np.r_[a.z, 0.0, -a.x] dz = {} dz[namea] = np.r_[b.y, -b.x, 0.0] dz[nameb] = np.r_[-a.y, a.x, 0.0] return dx, dy, dz def cross_deriv_array(self, other, namea="a", nameb="b"): # c = a X b a = self b = other dx = {} dx["d" + namea + "x"] = np.zeros_like(b.x) dx["d" + namea + "y"] = b.z dx["d" + namea + "z"] = -b.y dx["d" + nameb + "x"] = np.zeros_like(a.x) dx["d" + nameb + "y"] = -a.z dx["d" + nameb + "z"] = a.y dy = {} dy["d" + namea + "x"] = -b.z dy["d" + namea + "y"] = np.zeros_like(b.y) dy["d" + namea + "z"] = b.x dy["d" + nameb + "x"] = a.z dy["d" + nameb + "y"] = np.zeros_like(a.y) dy["d" + nameb + "z"] = -a.x dz = {} dz["d" + namea + "x"] = b.y dz["d" + namea + "y"] = -b.x dz["d" + namea + "z"] = np.zeros_like(b.z) dz["d" + nameb + "x"] = -a.y dz["d" + nameb + "y"] = a.x dz["d" + nameb + "z"] = np.zeros_like(a.z) return dx, dy, dz def __neg__(self): """negate direction vector""" return DirectionVector(-self.x, -self.y, -self.z) def __add__(self, other): """add two DirectionVector objects (v1 = v2 + v3)""" if isinstance(other, DirectionVector): return DirectionVector(self.x + other.x, self.y + other.y, self.z + other.z) else: return DirectionVector(self.x + other, self.y + other, self.z + other) def __sub__(self, other): """subtract DirectionVector objects (v1 = v2 - v3)""" if isinstance(other, DirectionVector): return DirectionVector(self.x - other.x, self.y - other.y, self.z - other.z) else: return DirectionVector(self.x - other, self.y - other, self.z - other) def __iadd__(self, other): """add DirectionVector object to self (v1 += v2)""" if isinstance(other, DirectionVector): self.x += other.x self.y += other.y self.z += other.z else: self.x += other self.y += other self.z += other return self def __isub__(self, other): """subract DirectionVector object from self (v1 -= v2)""" if isinstance(other, DirectionVector): self.x -= other.x self.y -= other.y self.z -= other.z else: self.x -= other self.y -= other self.z -= other return self def __mul__(self, other): """multiply vector times a scalar or element by element muiltiply times another vector (v1 = alpha * v2 or v1 = v2 * v3)""" if isinstance(other, DirectionVector): return DirectionVector(self.x * other.x, self.y * other.y, self.z * other.z) else: return DirectionVector(self.x * other, self.y * other, self.z * other) def __truediv__(self, other): """divide vector by a scalar or element by element division with another vector (v1 = v2 / alpha or v1 = v2 / v3)""" if isinstance(other, DirectionVector): return DirectionVector(self.x / other.x, self.y / other.y, self.z / other.z) else: return DirectionVector(self.x / float(other), self.y / float(other), self.z / float(other)) def __imul__(self, other): """multiply self times a scalar or element by element muiltiply times another vector (v1 *= alpha or v1 *= v2)""" if isinstance(other, DirectionVector): self.x *= other.x self.y *= other.y self.z *= other.z else: self.x *= other self.y *= other self.z *= other return self def __str__(self): """print string representation""" return "{0}, {1}, {2}".format(self.x, self.y, self.z)