def __residualDerivatives(self, phi, r, chord, theta, af, Vx, Vy): """derivatives of fzero, a, ap""" if self.iterRe != 1: ValueError('Analytic derivatives not supplied for case with iterRe > 1') # x = [phi, chord, theta, Vx, Vy, r, Rhub, Rtip] (derivative order) # alpha, Re (analytic derivaives) a = 0.0 ap = 0.0 alpha, W, Re = _bem.relativewind(phi, a, ap, Vx, Vy, self.pitch, chord, theta, self.rho, self.mu) dalpha_dx = np.array([1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0]) dRe_dx = np.array([0.0, Re/chord, 0.0, Re*Vx/W**2, Re*Vy/W**2, 0.0, 0.0, 0.0]) # cl, cd (spline derivatives) cl, cd = af.evaluate(alpha, Re) dcl_dalpha, dcl_dRe, dcd_dalpha, dcd_dRe = af.derivatives(alpha, Re) # chain rule dcl_dx = dcl_dalpha*dalpha_dx + dcl_dRe*dRe_dx dcd_dx = dcd_dalpha*dalpha_dx + dcd_dRe*dRe_dx # residual, a, ap (Tapenade) dx_dx = np.eye(8) fzero, a, ap, dR_dx, da_dx, dap_dx = _bem.inductionfactors_dv(r, chord, self.Rhub, self.Rtip, phi, cl, cd, self.B, Vx, Vy, dx_dx[5, :], dx_dx[1, :], dx_dx[6, :], dx_dx[7, :], dx_dx[0, :], dcl_dx, dcd_dx, dx_dx[3, :], dx_dx[4, :], **self.bemoptions) return dR_dx, da_dx, dap_dx
def __loads_nonRotating(self, chord, theta, af, Vx, Vy): """compute loads in batch for non-rotating case""" n = len(chord) W = np.zeros(n) cl = np.zeros(n) cd = np.zeros(n) for i in range(n): phi = pi/2.0 a = 0.0 ap = 0.0 alpha, W[i], Re = _bem.relativewind(phi, a, ap, Vx[i], Vy[i], self.pitch, chord[i], theta[i], self.rho, self.mu) cl[i], cd[i] = af[i].evaluate(alpha, Re) cn = cd ct = cl q = 0.5*self.rho*W**2 Np = cn*q*chord Tp = ct*q*chord return Np, Tp
def __residualDerivatives(self, phi, r, chord, theta, af, blend, Vx, Vy): """derivatives of fzero, a, ap""" if self.iterRe != 1: ValueError('Analytic derivatives not supplied for case with iterRe > 1') # x = [phi, chord, theta, Vx, Vy, r, Rhub, Rtip, pitch, blend] (derivative order) # alpha, Re (analytic derivaives) a = 0.0 ap = 0.0 alpha, W, Re = _bem.relativewind(phi, a, ap, Vx, Vy, self.pitch, chord, theta, self.rho, self.mu) dalpha_dx = np.array([1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0]) dRe_dx = np.array([0.0, Re/chord, 0.0, Re*Vx/W**2, Re*Vy/W**2, 0.0, 0.0, 0.0, 0.0, 0.0]) dblend_dx = np.array([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0]) # cl, cd (spline derivatives) cl, cd = af.evaluate(alpha, Re, blend) dcl_dalpha, dcl_dRe, dcd_dalpha, dcd_dRe, dcl_dblend, dcd_dblend = af.derivatives(alpha, Re, blend) # chain rule dcl_dx = dcl_dalpha*dalpha_dx + dcl_dRe*dRe_dx + dcl_dblend*dblend_dx dcd_dx = dcd_dalpha*dalpha_dx + dcd_dRe*dRe_dx + dcd_dblend*dblend_dx # residual, a, ap (Tapenade) dx_dx = np.eye(10) fzero, a, ap, dR_dx, da_dx, dap_dx = _bem.inductionfactors_dv(r, chord, self.Rhub, self.Rtip, phi, cl, cd, self.B, Vx, Vy, dx_dx[5, :], dx_dx[1, :], dx_dx[6, :], dx_dx[7, :], dx_dx[0, :], dcl_dx, dcd_dx, dx_dx[3, :], dx_dx[4, :], **self.bemoptions) return dR_dx, da_dx, dap_dx
def __loads(self, phi, r, chord, theta, af, Vx, Vy): """normal and tangential loads at one section (and optionally derivatives)""" cphi = cos(phi) sphi = sin(phi) zero, a, ap = self.__runBEM(phi, r, chord, theta, af, Vx, Vy) alpha, W, Re = _bem.relativewind(phi, a, ap, Vx, Vy, self.pitch, chord, theta, self.rho, self.mu) cl, cd = af.evaluate(alpha, Re) cn = cl*cphi + cd*sphi # these expressions should always contain drag ct = cl*sphi - cd*cphi q = 0.5*self.rho*W**2 Np = cn*q*chord Tp = ct*q*chord if not self.derivatives: return Np, Tp, 0.0, 0.0, 0.0 # derivative of residual function dR_dx, da_dx, dap_dx = self.__residualDerivatives(phi, r, chord, theta, af, Vx, Vy) # x = [phi, chord, theta, Vx, Vy, r, Rhub, Rtip] (derivative order) dx_dx = np.eye(8) dphi_dx = np.array([1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) dchord_dx = np.array([0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) # alpha, W, Re (Tapenade) alpha, W, Re, dalpha_dx, dW_dx, dRe_dx = _bem.relativewind_dv(phi, a, ap, Vx, Vy, self.pitch, chord, theta, self.rho, self.mu, dx_dx[0, :], da_dx, dap_dx, dx_dx[3, :], dx_dx[4, :], dx_dx[1, :], dx_dx[2, :]) # cl, cd (spline derivatives) dcl_dalpha, dcl_dRe, dcd_dalpha, dcd_dRe = af.derivatives(alpha, Re) # chain rule dcl_dx = dcl_dalpha*dalpha_dx + dcl_dRe*dRe_dx dcd_dx = dcd_dalpha*dalpha_dx + dcd_dRe*dRe_dx # cn, cd dcn_dx = dcl_dx*cphi - cl*sphi*dphi_dx + dcd_dx*sphi + cd*cphi*dphi_dx dct_dx = dcl_dx*sphi + cl*cphi*dphi_dx - dcd_dx*cphi + cd*sphi*dphi_dx # Np, Tp dNp_dx = Np*(1.0/cn*dcn_dx + 2.0/W*dW_dx + 1.0/chord*dchord_dx) dTp_dx = Tp*(1.0/ct*dct_dx + 2.0/W*dW_dx + 1.0/chord*dchord_dx) return Np, Tp, dNp_dx, dTp_dx, dR_dx
def __runBEM(self, phi, r, chord, theta, af, Vx, Vy): """residual of BEM method and other corresponding variables""" a = 0.0 ap = 0.0 for i in range(self.iterRe): alpha, W, Re = _bem.relativewind(phi, a, ap, Vx, Vy, self.pitch, chord, theta, self.rho, self.mu) cl, cd = af.evaluate(alpha, Re) fzero, a, ap = _bem.inductionfactors(r, chord, self.Rhub, self.Rtip, phi, cl, cd, self.B, Vx, Vy, **self.bemoptions) return fzero, a, ap
def __runBEM(self, phi, r, chord, theta, af, blend, Vx, Vy): """residual of BEM method and other corresponding variables""" a = 0.0 ap = 0.0 for i in range(self.iterRe): alpha, W, Re = _bem.relativewind(phi, a, ap, Vx, Vy, self.pitch, chord, theta, self.rho, self.mu) cl, cd = af.evaluate(alpha, Re, blend) fzero, a, ap = _bem.inductionfactors(r, chord, self.Rhub, self.Rtip, phi, cl, cd, self.B, Vx, Vy, **self.bemoptions) return fzero, a, ap
def __loads(self, phi, rotating, r, chord, theta, af, Vx, Vy): """normal and tangential loads at one section (and optionally derivatives)""" cphi = cos(phi) sphi = sin(phi) if rotating: _, a, ap = self.__runBEM(phi, r, chord, theta, af, Vx, Vy) else: a = 0.0 ap = 0.0 alpha, W, Re = _bem.relativewind(phi, a, ap, Vx, Vy, self.pitch, chord, theta, self.rho, self.mu) cl, cd = af.evaluate(alpha, Re) cn = cl * cphi + cd * sphi # these expressions should always contain drag ct = cl * sphi - cd * cphi q = 0.5 * self.rho * W**2 Np = cn * q * chord Tp = ct * q * chord if not self.derivatives: return Np, Tp, 0.0, 0.0, 0.0 # derivative of residual function if rotating: dR_dx, da_dx, dap_dx = self.__residualDerivatives( phi, r, chord, theta, af, Vx, Vy) dphi_dx = np.array([1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) else: dR_dx = np.zeros(9) dR_dx[0] = 1.0 # just to prevent divide by zero da_dx = np.zeros(9) dap_dx = np.zeros(9) dphi_dx = np.zeros(9) # x = [phi, chord, theta, Vx, Vy, r, Rhub, Rtip, pitch] (derivative order) dx_dx = np.eye(9) dchord_dx = np.array([0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) # alpha, W, Re (Tapenade) alpha, dalpha_dx, W, dW_dx, Re, dRe_dx = _bem.relativewind_dv( phi, dx_dx[0, :], a, da_dx, ap, dap_dx, Vx, dx_dx[3, :], Vy, dx_dx[4, :], self.pitch, dx_dx[8, :], chord, dx_dx[1, :], theta, dx_dx[2, :], self.rho, self.mu) # cl, cd (spline derivatives) dcl_dalpha, dcl_dRe, dcd_dalpha, dcd_dRe = af.derivatives(alpha, Re) # chain rule dcl_dx = dcl_dalpha * dalpha_dx + dcl_dRe * dRe_dx dcd_dx = dcd_dalpha * dalpha_dx + dcd_dRe * dRe_dx # cn, cd dcn_dx = dcl_dx * cphi - cl * sphi * dphi_dx + dcd_dx * sphi + cd * cphi * dphi_dx dct_dx = dcl_dx * sphi + cl * cphi * dphi_dx - dcd_dx * cphi + cd * sphi * dphi_dx # Np, Tp dNp_dx = Np * (1.0 / cn * dcn_dx + 2.0 / W * dW_dx + 1.0 / chord * dchord_dx) dTp_dx = Tp * (1.0 / ct * dct_dx + 2.0 / W * dW_dx + 1.0 / chord * dchord_dx) return Np, Tp, dNp_dx, dTp_dx, dR_dx
def __loads(self, phi, rotating, r, chord, theta, af, Vx, Vy): """normal and tangential loads at one section (and optionally derivatives)""" cphi = cos(phi) sphi = sin(phi) if rotating: _, a, ap = self.__runBEM(phi, r, chord, theta, af, Vx, Vy) else: a = 0.0 ap = 0.0 alpha_rad, W, Re = _bem.relativewind(phi, a, ap, Vx, Vy, self.pitch, chord, theta, self.rho, self.mu) cl, cd = af.evaluate(alpha_rad, Re) cn = cl*cphi + cd*sphi # these expressions should always contain drag ct = cl*sphi - cd*cphi q = 0.5*self.rho*W**2 Np = cn*q*chord Tp = ct*q*chord alpha_deg = alpha_rad * 180. / np.pi if not self.derivatives: return a, ap, Np, Tp, alpha_deg, 0.0, 0.0, 0.0 # derivative of residual function if rotating: dR_dx, da_dx, dap_dx = self.__residualDerivatives(phi, r, chord, theta, af, Vx, Vy) dphi_dx = np.array([1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) else: dR_dx = np.zeros(9) dR_dx[0] = 1.0 # just to prevent divide by zero da_dx = np.zeros(9) dap_dx = np.zeros(9) dphi_dx = np.zeros(9) # x = [phi, chord, theta, Vx, Vy, r, Rhub, Rtip, pitch] (derivative order) dx_dx = np.eye(9) dchord_dx = np.array([0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) # alpha, W, Re (Tapenade) alpha_rad, dalpha_dx, W, dW_dx, Re, dRe_dx = _bem.relativewind_dv(phi, dx_dx[0, :], a, da_dx, ap, dap_dx, Vx, dx_dx[3, :], Vy, dx_dx[4, :], self.pitch, dx_dx[8, :], chord, dx_dx[1, :], theta, dx_dx[2, :], self.rho, self.mu) # cl, cd (spline derivatives) dcl_dalpha, dcl_dRe, dcd_dalpha, dcd_dRe = af.derivatives(alpha_rad, Re) # chain rule dcl_dx = dcl_dalpha*dalpha_dx + dcl_dRe*dRe_dx dcd_dx = dcd_dalpha*dalpha_dx + dcd_dRe*dRe_dx # cn, cd dcn_dx = dcl_dx*cphi - cl*sphi*dphi_dx + dcd_dx*sphi + cd*cphi*dphi_dx dct_dx = dcl_dx*sphi + cl*cphi*dphi_dx - dcd_dx*cphi + cd*sphi*dphi_dx # Np, Tp dNp_dx = Np*(1.0/cn*dcn_dx + 2.0/W*dW_dx + 1.0/chord*dchord_dx) dTp_dx = Tp*(1.0/ct*dct_dx + 2.0/W*dW_dx + 1.0/chord*dchord_dx) alpha_deg = alpha_rad * 180. / np.pi return a, ap, Np, Tp, alpha_deg, dNp_dx, dTp_dx, dR_dx