def provideJ(self): V = self.V R = self.R CT = self.CT CQ = self.CQ CP = self.CP n = len(self.V) q = 0.5 * self.rho * V**2 A = pi * R**2 zeronn = np.zeros((n, n)) dCT_dV = np.diag(-2.0*CT/V) dCT_dT = np.diag(1.0/(q*A)) dCT_dR = -2.0*CT/R dCT = hstack((dCT_dV, dCT_dT, zeronn, zeronn, dCT_dR)) dCQ_dV = np.diag(-2.0*CQ/V) dCQ_dQ = np.diag(1.0/(q*R*A)) dCQ_dR = -3.0*CQ/R dCQ = hstack((dCQ_dV, zeronn, dCQ_dQ, zeronn, dCQ_dR)) dCP_dV = np.diag(-3.0*CP/V) dCP_dP = np.diag(1.0/(q*A*V)) dCP_dR = -2.0*CP/R dCP = hstack((dCP_dV, zeronn, zeronn, dCP_dP, dCP_dR)) J = vstack((dCT, dCQ, dCP)) return J
def linearize(self, params, unknowns, resids): dF = DirectionVector.fromArray(params['F']).hubToYaw(params['tilt']) dFx, dFy, dFz = dF.dx, dF.dy, dF.dz dtopF_dFx = np.array([dFx['dx'], dFy['dx'], dFz['dx']]) dtopF_dFy = np.array([dFx['dy'], dFy['dy'], dFz['dy']]) dtopF_dFz = np.array([dFx['dz'], dFy['dz'], dFz['dz']]) dtopF_dF = hstack([dtopF_dFx, dtopF_dFy, dtopF_dFz]) dtopF_w_dm = np.array([0.0, 0.0, -self.g]) #dtopF = hstack([dtopF_dF, np.zeros((3, 6)), dtopF_w_dm, np.zeros((3, 3))]) dM = DirectionVector.fromArray(params['M']).hubToYaw(params['tilt']) dMx, dMy, dMz = dM.dx, dM.dy, dM.dz dMxcross, dMycross, dMzcross = self.save_rhub.cross_deriv(self.saveF, 'dr', 'dF') dtopM_dMx = np.array([dMx['dx'], dMy['dx'], dMz['dx']]) dtopM_dMy = np.array([dMx['dy'], dMy['dy'], dMz['dy']]) dtopM_dMz = np.array([dMx['dz'], dMy['dz'], dMz['dz']]) dtopM_dM = hstack([dtopM_dMx, dtopM_dMy, dtopM_dMz]) dM_dF = np.array([dMxcross['dF'], dMycross['dF'], dMzcross['dF']]) dtopM_dFx = np.dot(dM_dF, dtopF_dFx) dtopM_dFy = np.dot(dM_dF, dtopF_dFy) dtopM_dFz = np.dot(dM_dF, dtopF_dFz) dtopM_dF = hstack([dtopM_dFx, dtopM_dFy, dtopM_dFz]) dtopM_dr = np.array([dMxcross['dr'], dMycross['dr'], dMzcross['dr']]) dMx_w_cross, dMy_w_cross, dMz_w_cross = self.save_rcm.cross_deriv(self.saveF_w, 'dr', 'dF') if params['rna_weightM']: dtopM_drnacm = np.array([dMx_w_cross['dr'], dMy_w_cross['dr'], dMz_w_cross['dr']]) dtopM_dF_w = np.array([dMx_w_cross['dF'], dMy_w_cross['dF'], dMz_w_cross['dF']]) else: dtopM_drnacm = np.zeros((3, 3)) dtopM_dF_w = np.zeros((3, 3)) dtopM_dm = np.dot(dtopM_dF_w, dtopF_w_dm) if params['downwind']: dtopM_dr[:, 0] *= -1 dtopM_drnacm[:, 0] *= -1 #dtopM = hstack([dtopM_dF, dtopM_dM, dtopM_dr, dtopM_dm, dtopM_drnacm]) J = {} J['top_F', 'F'] = dtopF_dF J['top_F', 'M'] = np.zeros((3, 3)) J['top_F', 'r_hub'] = np.zeros((3, 3)) J['top_F', 'rna_mass'] = dtopF_w_dm J['top_F', 'rna_cm'] = np.zeros((3, 3)) J['top_M', 'F'] = dtopM_dF J['top_M', 'M'] = dtopM_dM J['top_M', 'r_hub'] = dtopM_dr J['top_M', 'rna_mass'] = dtopM_dm J['top_M', 'rna_cm'] = dtopM_drnacm return J
def provideJ(self): dF = DirectionVector.fromArray(self.F).hubToYaw(self.tilt) dFx, dFy, dFz = dF.dx, dF.dy, dF.dz dtopF_dFx = np.array([dFx['dx'], dFy['dx'], dFz['dx']]) dtopF_dFy = np.array([dFx['dy'], dFy['dy'], dFz['dy']]) dtopF_dFz = np.array([dFx['dz'], dFy['dz'], dFz['dz']]) dtopF_dF = hstack([dtopF_dFx, dtopF_dFy, dtopF_dFz]) dtopF_w_dm = np.array([0.0, 0.0, -self.g]) dtopF = hstack( [dtopF_dF, np.zeros((3, 6)), dtopF_w_dm, np.zeros((3, 3))]) dM = DirectionVector.fromArray(self.M).hubToYaw(self.tilt) dMx, dMy, dMz = dM.dx, dM.dy, dM.dz dMxcross, dMycross, dMzcross = self.save_rhub.cross_deriv( self.saveF, 'dr', 'dF') dtopM_dMx = np.array([dMx['dx'], dMy['dx'], dMz['dx']]) dtopM_dMy = np.array([dMx['dy'], dMy['dy'], dMz['dy']]) dtopM_dMz = np.array([dMx['dz'], dMy['dz'], dMz['dz']]) dtopM_dM = hstack([dtopM_dMx, dtopM_dMy, dtopM_dMz]) dM_dF = np.array([dMxcross['dF'], dMycross['dF'], dMzcross['dF']]) dtopM_dFx = np.dot(dM_dF, dtopF_dFx) dtopM_dFy = np.dot(dM_dF, dtopF_dFy) dtopM_dFz = np.dot(dM_dF, dtopF_dFz) dtopM_dF = hstack([dtopM_dFx, dtopM_dFy, dtopM_dFz]) dtopM_dr = np.array([dMxcross['dr'], dMycross['dr'], dMzcross['dr']]) dMx_w_cross, dMy_w_cross, dMz_w_cross = self.save_rcm.cross_deriv( self.saveF_w, 'dr', 'dF') if self.rna_weightM: dtopM_drnacm = np.array( [dMx_w_cross['dr'], dMy_w_cross['dr'], dMz_w_cross['dr']]) dtopM_dF_w = np.array( [dMx_w_cross['dF'], dMy_w_cross['dF'], dMz_w_cross['dF']]) else: dtopM_drnacm = np.zeros((3, 3)) dtopM_dF_w = np.zeros((3, 3)) dtopM_dm = np.dot(dtopM_dF_w, dtopF_w_dm) if self.downwind: dtopM_dr[:, 0] *= -1 dtopM_drnacm[:, 0] *= -1 dtopM = hstack([dtopM_dF, dtopM_dM, dtopM_dr, dtopM_dm, dtopM_drnacm]) J = vstack([dtopF, dtopM]) return J
def provideJ(self): dF = DirectionVector.fromArray(self.F).hubToYaw(self.tilt) dFx, dFy, dFz = dF.dx, dF.dy, dF.dz dtopF_dFx = np.array([dFx['dx'], dFy['dx'], dFz['dx']]) dtopF_dFy = np.array([dFx['dy'], dFy['dy'], dFz['dy']]) dtopF_dFz = np.array([dFx['dz'], dFy['dz'], dFz['dz']]) dtopF_dF = hstack([dtopF_dFx, dtopF_dFy, dtopF_dFz]) dtopF_w_dm = np.array([0.0, 0.0, -self.g]) dtopF = hstack([dtopF_dF, np.zeros((3, 6)), dtopF_w_dm, np.zeros((3, 3))]) dM = DirectionVector.fromArray(self.M).hubToYaw(self.tilt) dMx, dMy, dMz = dM.dx, dM.dy, dM.dz dMxcross, dMycross, dMzcross = self.save_rhub.cross_deriv(self.saveF, 'dr', 'dF') dtopM_dMx = np.array([dMx['dx'], dMy['dx'], dMz['dx']]) dtopM_dMy = np.array([dMx['dy'], dMy['dy'], dMz['dy']]) dtopM_dMz = np.array([dMx['dz'], dMy['dz'], dMz['dz']]) dtopM_dM = hstack([dtopM_dMx, dtopM_dMy, dtopM_dMz]) dM_dF = np.array([dMxcross['dF'], dMycross['dF'], dMzcross['dF']]) dtopM_dFx = np.dot(dM_dF, dtopF_dFx) dtopM_dFy = np.dot(dM_dF, dtopF_dFy) dtopM_dFz = np.dot(dM_dF, dtopF_dFz) dtopM_dF = hstack([dtopM_dFx, dtopM_dFy, dtopM_dFz]) dtopM_dr = np.array([dMxcross['dr'], dMycross['dr'], dMzcross['dr']]) dMx_w_cross, dMy_w_cross, dMz_w_cross = self.save_rcm.cross_deriv(self.saveF_w, 'dr', 'dF') if self.rna_weightM: dtopM_drnacm = np.array([dMx_w_cross['dr'], dMy_w_cross['dr'], dMz_w_cross['dr']]) dtopM_dF_w = np.array([dMx_w_cross['dF'], dMy_w_cross['dF'], dMz_w_cross['dF']]) else: dtopM_drnacm = np.zeros((3, 3)) dtopM_dF_w = np.zeros((3, 3)) dtopM_dm = np.dot(dtopM_dF_w, dtopF_w_dm) if self.downwind: dtopM_dr[:, 0] *= -1 dtopM_drnacm[:, 0] *= -1 dtopM = hstack([dtopM_dF, dtopM_dM, dtopM_dr, dtopM_dm, dtopM_drnacm]) J = vstack([dtopF, dtopM]) return J
def execute(self): ctrl = self.control n = self.npts R = self.R # # attempt to distribute points mostly before rated # cpguess = 0.5 # Vr0 = (ctrl.ratedPower/(cpguess*0.5*rho*pi*R**2))**(1.0/3) # Vr0 *= 1.20 # V1 = np.linspace(Vin, Vr0, 15) # V2 = np.linspace(Vr0, Vout, 6) # V = np.concatenate([V1, V2[1:]]) # velocity sweep V = np.linspace(ctrl.Vin, ctrl.Vout, n) # corresponding rotation speed Omega_d = ctrl.tsr*V/R*RS2RPM Omega, dOmega_dOmegad, dOmega_dmaxOmega = smooth_min(Omega_d, ctrl.maxOmega, pct_offset=0.01) # store values self.Uhub = V self.Omega = Omega self.pitch = ctrl.pitch*np.ones_like(V) # gradients dV = np.zeros((n, 3)) dOmega_dtsr = dOmega_dOmegad * V/R*RS2RPM dOmega_dR = dOmega_dOmegad * -ctrl.tsr*V/R**2*RS2RPM dOmega = hstack([dOmega_dtsr, dOmega_dR, dOmega_dmaxOmega]) dpitch = np.zeros((n, 3)) self.J = vstack([dV, dOmega, dpitch])
def provideJ(self): x = self.x xbar = self.xbar dx = np.diag(np.exp(-pi/4.0*(x/xbar)**2)*pi*x/(2.0*xbar**2)) dxbar = -np.exp(-pi/4.0*(x/xbar)**2)*pi*x**2/(2.0*xbar**3) J = hstack([dx, dxbar]) return J
def provideJ(self): # mass dmass = np.hstack([np.array([1.0, 1.0, 1.0]), np.zeros(2*3+3*6)]) # cm top = (self.rotor_mass*self.hub_cm + self.nac_mass*self.nac_cm) dcm_dblademass = (self.rna_mass*self.hub_cm - top)/self.rna_mass**2 dcm_dhubmass = (self.rna_mass*self.hub_cm - top)/self.rna_mass**2 dcm_dnacmass = (self.rna_mass*self.nac_cm - top)/self.rna_mass**2 dcm_dhubcm = self.rotor_mass/self.rna_mass*np.eye(3) dcm_dnaccm = self.nac_mass/self.rna_mass*np.eye(3) dcm = hstack([dcm_dblademass, dcm_dhubmass, dcm_dnacmass, dcm_dhubcm, dcm_dnaccm, np.zeros((3, 3*6))]) # I R = self.hub_cm const = self._unassembleI(np.dot(R, R)*np.eye(3) - np.outer(R, R)) dI_dblademass = const dI_dhubmass = const dI_drx = self.rotor_mass*self._unassembleI(2*R[0]*np.eye(3) - np.array([[2*R[0], R[1], R[2]], [R[1], 0.0, 0.0], [R[2], 0.0, 0.0]])) dI_dry = self.rotor_mass*self._unassembleI(2*R[1]*np.eye(3) - np.array([[0.0, R[0], 0.0], [R[0], 2*R[1], R[2]], [0.0, R[2], 0.0]])) dI_drz = self.rotor_mass*self._unassembleI(2*R[2]*np.eye(3) - np.array([[0.0, 0.0, R[0]], [0.0, 0.0, R[1]], [R[0], R[1], 2*R[2]]])) dI_dhubcm = np.vstack([dI_drx, dI_dry, dI_drz]).T R = self.nac_cm const = self._unassembleI(np.dot(R, R)*np.eye(3) - np.outer(R, R)) dI_dnacmass = const dI_drx = self.nac_mass*self._unassembleI(2*R[0]*np.eye(3) - np.array([[2*R[0], R[1], R[2]], [R[1], 0.0, 0.0], [R[2], 0.0, 0.0]])) dI_dry = self.nac_mass*self._unassembleI(2*R[1]*np.eye(3) - np.array([[0.0, R[0], 0.0], [R[0], 2*R[1], R[2]], [0.0, R[2], 0.0]])) dI_drz = self.nac_mass*self._unassembleI(2*R[2]*np.eye(3) - np.array([[0.0, 0.0, R[0]], [0.0, 0.0, R[1]], [R[0], R[1], 2*R[2]]])) dI_dnaccm = np.vstack([dI_drx, dI_dry, dI_drz]).T dI_dbladeI = np.eye(6) dI_dhubI = np.eye(6) dI_dnacI = np.eye(6) dI = hstack([dI_dblademass, dI_dhubmass, dI_dnacmass, dI_dhubcm, dI_dnaccm, dI_dbladeI, dI_dhubI, dI_dnacI]) J = np.vstack([dmass, dcm, dI]) return J
def provideJ(self): x = self.x k = self.k A = self.xbar / gamma(1.0 + 1.0/k) dx = np.diag(np.exp(-(x/A)**k)*(x/A)**(k-1)*k/A) dxbar = -np.exp(-(x/A)**k)*(x/A)**(k-1)*k*x/A**2/gamma(1.0 + 1.0/k) J = hstack([dx, dxbar]) return J
def provideJ(self): x = self.x xbar = self.xbar dx = np.diag( np.exp(-pi / 4.0 * (x / xbar)**2) * pi * x / (2.0 * xbar**2)) dxbar = -np.exp(-pi / 4.0 * (x / xbar)**2) * pi * x**2 / (2.0 * xbar**3) J = hstack([dx, dxbar]) return J
def execute(self): ctrl = self.control n = self.npts # finer power curve self.V, _, _ = linspace_with_deriv(ctrl.Vin, ctrl.Vout, n) spline = Akima(self.Vcoarse, self.Pcoarse) self.P, dP_dV, dP_dVcoarse, dP_dPcoarse = spline.interp(self.V) self.J = hstack([dP_dVcoarse, dP_dPcoarse])
def execute(self): drivetrainType = self.drivetrainType aeroPower = self.aeroPower aeroTorque = self.aeroTorque ratedPower = self.ratedPower if drivetrainType == 'geared': constant = 0.01289 linear = 0.08510 quadratic = 0.0 elif drivetrainType == 'single_stage': constant = 0.01331 linear = 0.03655 quadratic = 0.06107 elif drivetrainType == 'multi_drive': constant = 0.01547 linear = 0.04463 quadratic = 0.05790 elif drivetrainType == 'pm_direct_drive': constant = 0.01007 linear = 0.02000 quadratic = 0.06899 Pbar0 = aeroPower / ratedPower # handle negative power case (with absolute value) Pbar1, dPbar1_dPbar0 = smooth_abs(Pbar0, dx=0.01) # truncate idealized power curve for purposes of efficiency calculation Pbar, dPbar_dPbar1, _ = smooth_min(Pbar1, 1.0, pct_offset=0.01) # compute efficiency eff = 1.0 - (constant/Pbar + linear + quadratic*Pbar) self.power = aeroPower * eff # gradients dPbar_dPa = dPbar_dPbar1*dPbar1_dPbar0/ratedPower dPbar_dPr = -dPbar_dPbar1*dPbar1_dPbar0*aeroPower/ratedPower**2 deff_dPa = dPbar_dPa*(constant/Pbar**2 - quadratic) deff_dPr = dPbar_dPr*(constant/Pbar**2 - quadratic) dP_dPa = eff + aeroPower*deff_dPa dP_dPr = aeroPower*deff_dPr self.J = hstack([np.diag(dP_dPa), dP_dPr])
def provideJ(self): x = self.x k = self.k A = self.xbar / gamma(1.0 + 1.0 / k) dx = np.diag(np.exp(-(x / A)**k) * (x / A)**(k - 1) * k / A) dxbar = -np.exp(-(x / A)**k) * (x / A)**( k - 1) * k * x / A**2 / gamma(1.0 + 1.0 / k) J = hstack([dx, dxbar]) return J
def execute(self): drivetrainType = self.drivetrainType aeroPower = self.aeroPower aeroTorque = self.aeroTorque ratedPower = self.ratedPower if drivetrainType == 'geared': constant = 0.01289 linear = 0.08510 quadratic = 0.0 elif drivetrainType == 'single_stage': constant = 0.01331 linear = 0.03655 quadratic = 0.06107 elif drivetrainType == 'multi_drive': constant = 0.01547 linear = 0.04463 quadratic = 0.05790 elif drivetrainType == 'pm_direct_drive': constant = 0.01007 linear = 0.02000 quadratic = 0.06899 Pbar0 = aeroPower / ratedPower # handle negative power case (with absolute value) Pbar1, dPbar1_dPbar0 = smooth_abs(Pbar0, dx=0.01) # truncate idealized power curve for purposes of efficiency calculation Pbar, dPbar_dPbar1, _ = smooth_min(Pbar1, 1.0, pct_offset=0.01) # compute efficiency eff = 1.0 - (constant / Pbar + linear + quadratic * Pbar) self.power = aeroPower * eff # gradients dPbar_dPa = dPbar_dPbar1 * dPbar1_dPbar0 / ratedPower dPbar_dPr = -dPbar_dPbar1 * dPbar1_dPbar0 * aeroPower / ratedPower**2 deff_dPa = dPbar_dPa * (constant / Pbar**2 - quadratic) deff_dPr = dPbar_dPr * (constant / Pbar**2 - quadratic) dP_dPa = eff + aeroPower * deff_dPa dP_dPr = aeroPower * deff_dPr self.J = hstack([np.diag(dP_dPa), dP_dPr])
def provideJ(self): if self.run_case == 'power': dP = self.dP dT = self.dT dQ = self.dQ jP = hstack([dP['dprecone'], dP['dtilt'], dP['dhubHt'], dP['dRhub'], dP['dRtip'], dP['dyaw'], dP['dUinf'], dP['dOmega'], dP['dpitch'], dP['dr'], dP['dchord'], dP['dtheta'], dP['dprecurve'], dP['dprecurveTip']]) jT = hstack([dT['dprecone'], dT['dtilt'], dT['dhubHt'], dT['dRhub'], dT['dRtip'], dT['dyaw'], dT['dUinf'], dT['dOmega'], dT['dpitch'], dT['dr'], dT['dchord'], dT['dtheta'], dT['dprecurve'], dT['dprecurveTip']]) jQ = hstack([dQ['dprecone'], dQ['dtilt'], dQ['dhubHt'], dQ['dRhub'], dQ['dRtip'], dQ['dyaw'], dQ['dUinf'], dQ['dOmega'], dQ['dpitch'], dQ['dr'], dQ['dchord'], dQ['dtheta'], dQ['dprecurve'], dQ['dprecurveTip']]) J = vstack([jP, jT, jQ]) elif self.run_case == 'loads': dNp = self.dNp dTp = self.dTp n = len(self.r) dr_dr = vstack([np.zeros(n), np.eye(n), np.zeros(n)]) dr_dRhub = np.zeros(n+2) dr_dRtip = np.zeros(n+2) dr_dRhub[0] = 1.0 dr_dRtip[-1] = 1.0 dr = hstack([dr_dr, np.zeros((n+2, 2*n)), dr_dRhub, dr_dRtip, np.zeros((n+2, 8+n))]) jNp = hstack([dNp['dr'], dNp['dchord'], dNp['dtheta'], dNp['dRhub'], dNp['dRtip'], dNp['dhubHt'], dNp['dprecone'], dNp['dtilt'], dNp['dyaw'], dNp['dUinf'], dNp['dOmega'], dNp['dpitch'], dNp['dazimuth'], dNp['dprecurve']]) jTp = hstack([dTp['dr'], dTp['dchord'], dTp['dtheta'], dTp['dRhub'], dTp['dRtip'], dTp['dhubHt'], dTp['dprecone'], dTp['dtilt'], dTp['dyaw'], dTp['dUinf'], dTp['dOmega'], dTp['dpitch'], dTp['dazimuth'], dTp['dprecurve']]) dPx = vstack([np.zeros(4*n+10), jNp, np.zeros(4*n+10)]) dPy = vstack([np.zeros(4*n+10), -jTp, np.zeros(4*n+10)]) dPz = np.zeros((n+2, 4*n+10)) dV = np.zeros(4*n+10) dV[3*n+6] = 1.0 dOmega = np.zeros(4*n+10) dOmega[3*n+7] = 1.0 dpitch = np.zeros(4*n+10) dpitch[3*n+8] = 1.0 dazimuth = np.zeros(4*n+10) dazimuth[3*n+9] = 1.0 J = vstack([dr, dPx, dPy, dPz, dV, dOmega, dpitch, dazimuth]) return J
def provideJ(self): # mass dmass = np.hstack([np.array([1.0, 1.0, 1.0]), np.zeros(2 * 3 + 3 * 6)]) # cm top = (self.rotor_mass * self.hub_cm + self.nac_mass * self.nac_cm) dcm_dblademass = (self.rna_mass * self.hub_cm - top) / self.rna_mass**2 dcm_dhubmass = (self.rna_mass * self.hub_cm - top) / self.rna_mass**2 dcm_dnacmass = (self.rna_mass * self.nac_cm - top) / self.rna_mass**2 dcm_dhubcm = self.rotor_mass / self.rna_mass * np.eye(3) dcm_dnaccm = self.nac_mass / self.rna_mass * np.eye(3) dcm = hstack([ dcm_dblademass, dcm_dhubmass, dcm_dnacmass, dcm_dhubcm, dcm_dnaccm, np.zeros((3, 3 * 6)) ]) # I R = self.hub_cm const = self._unassembleI(np.dot(R, R) * np.eye(3) - np.outer(R, R)) dI_dblademass = const dI_dhubmass = const dI_drx = self.rotor_mass * self._unassembleI( 2 * R[0] * np.eye(3) - np.array([[2 * R[0], R[1], R[2]], [R[1], 0.0, 0.0], [R[2], 0.0, 0.0]])) dI_dry = self.rotor_mass * self._unassembleI( 2 * R[1] * np.eye(3) - np.array([[0.0, R[0], 0.0], [R[0], 2 * R[1], R[2]], [0.0, R[2], 0.0]])) dI_drz = self.rotor_mass * self._unassembleI( 2 * R[2] * np.eye(3) - np.array( [[0.0, 0.0, R[0]], [0.0, 0.0, R[1]], [R[0], R[1], 2 * R[2]]])) dI_dhubcm = np.vstack([dI_drx, dI_dry, dI_drz]).T R = self.nac_cm const = self._unassembleI(np.dot(R, R) * np.eye(3) - np.outer(R, R)) dI_dnacmass = const dI_drx = self.nac_mass * self._unassembleI( 2 * R[0] * np.eye(3) - np.array([[2 * R[0], R[1], R[2]], [R[1], 0.0, 0.0], [R[2], 0.0, 0.0]])) dI_dry = self.nac_mass * self._unassembleI( 2 * R[1] * np.eye(3) - np.array([[0.0, R[0], 0.0], [R[0], 2 * R[1], R[2]], [0.0, R[2], 0.0]])) dI_drz = self.nac_mass * self._unassembleI( 2 * R[2] * np.eye(3) - np.array( [[0.0, 0.0, R[0]], [0.0, 0.0, R[1]], [R[0], R[1], 2 * R[2]]])) dI_dnaccm = np.vstack([dI_drx, dI_dry, dI_drz]).T dI_dbladeI = np.eye(6) dI_dhubI = np.eye(6) dI_dnacI = np.eye(6) dI = hstack([ dI_dblademass, dI_dhubmass, dI_dnacmass, dI_dhubcm, dI_dnaccm, dI_dbladeI, dI_dhubI, dI_dnacI ]) J = np.vstack([dmass, dcm, dI]) return J
def execute(self): nc = len(self.chord_sub) nt = len(self.theta_sub) Rhub = self.Rhub Rtip = self.Rtip idxc = self.idx_cylinder r_max_chord = Rhub + (Rtip-Rhub)*self.r_max_chord r_cylinder = Rhub + (Rtip-Rhub)*self.r_af[idxc] # chord parameterization rc_outer, drc_drcmax, drc_drtip = linspace_with_deriv(r_max_chord, Rtip, nc-1) r_chord = np.concatenate([[Rhub], rc_outer]) drc_drcmax = np.concatenate([[0.0], drc_drcmax]) drc_drtip = np.concatenate([[0.0], drc_drtip]) drc_drhub = np.concatenate([[1.0], np.zeros(nc-1)]) # theta parameterization r_theta, drt_drcyl, drt_drtip = linspace_with_deriv(r_cylinder, Rtip, nt) # spline chord_spline = Akima(r_chord, self.chord_sub) theta_spline = Akima(r_theta, self.theta_sub) self.r = Rhub + (Rtip-Rhub)*self.r_af self.chord, dchord_dr, dchord_drchord, dchord_dchordsub = chord_spline.interp(self.r) theta_outer, dthetaouter_dr, dthetaouter_drtheta, dthetaouter_dthetasub = theta_spline.interp(self.r[idxc:]) theta_inner = theta_outer[0] * np.ones(idxc) self.theta = np.concatenate([theta_inner, theta_outer]) self.r_af_spacing = np.diff(self.r_af) self.precurve = np.zeros_like(self.chord) # TODO: for now I'm forcing this to zero, just for backwards compatibility # gradients (TODO: rethink these a bit or use Tapenade.) n = len(self.r_af) dr_draf = (Rtip-Rhub)*np.ones(n) dr_dRhub = 1.0 - self.r_af dr_dRtip = self.r_af dr = hstack([np.diag(dr_draf), np.zeros((n, 1)), dr_dRhub, dr_dRtip, np.zeros((n, nc+nt))]) dchord_draf = dchord_dr * dr_draf dchord_drmaxchord0 = np.dot(dchord_drchord, drc_drcmax) dchord_drmaxchord = dchord_drmaxchord0 * (Rtip-Rhub) dchord_drhub = np.dot(dchord_drchord, drc_drhub) + dchord_drmaxchord0*(1.0 - self.r_max_chord) + dchord_dr*dr_dRhub dchord_drtip = np.dot(dchord_drchord, drc_drtip) + dchord_drmaxchord0*(self.r_max_chord) + dchord_dr*dr_dRtip dchord = hstack([np.diag(dchord_draf), dchord_drmaxchord, dchord_drhub, dchord_drtip, dchord_dchordsub, np.zeros((n, nt))]) dthetaouter_dcyl = np.dot(dthetaouter_drtheta, drt_drcyl) dthetaouter_draf = dthetaouter_dr*dr_draf[idxc:] dthetaouter_drhub = dthetaouter_dr*dr_dRhub[idxc:] dthetaouter_drtip = dthetaouter_dr*dr_dRtip[idxc:] + np.dot(dthetaouter_drtheta, drt_drtip) dtheta_draf = np.concatenate([np.zeros(idxc), dthetaouter_draf]) dtheta_drhub = np.concatenate([dthetaouter_drhub[0]*np.ones(idxc), dthetaouter_drhub]) dtheta_drtip = np.concatenate([dthetaouter_drtip[0]*np.ones(idxc), dthetaouter_drtip]) sub = dthetaouter_dthetasub[0, :] dtheta_dthetasub = vstack([np.dot(np.ones((idxc, 1)), sub[np.newaxis, :]), dthetaouter_dthetasub]) dtheta_draf = np.diag(dtheta_draf) dtheta_dcyl = np.concatenate([dthetaouter_dcyl[0]*np.ones(idxc), dthetaouter_dcyl]) dtheta_draf[idxc:, idxc] += dthetaouter_dcyl*(Rtip-Rhub) dtheta_drhub += dtheta_dcyl*(1.0 - self.r_af[idxc]) dtheta_drtip += dtheta_dcyl*self.r_af[idxc] dtheta = hstack([dtheta_draf, np.zeros((n, 1)), dtheta_drhub, dtheta_drtip, np.zeros((n, nc)), dtheta_dthetasub]) drafs_dr = np.zeros((n-1, n)) for i in range(n-1): drafs_dr[i, i] = -1.0 drafs_dr[i, i+1] = 1.0 drafs = hstack([drafs_dr, np.zeros((n-1, 3+nc+nt))]) dprecurve = np.zeros((len(self.precurve), n+3+nc+nt)) self.J = vstack([dr, dchord, dtheta, drafs, dprecurve])
def provideJ(self): dbyx = self.blade_yaw.dx # dbyy = self.blade_yaw.dy dbyz = self.blade_yaw.dz # Rtip drtower_dRtip = self.drtower_dztower * dbyz['dz'] / self.towerHt if self.precone >= 0: dtd_dRtip = -dbyx['dz'] - drtower_dRtip else: dtd_dRtip = dbyx['dz'] - drtower_dRtip dgc_dRtip = dbyz['dz'] # precurveTip drtower_dprecurveTip = self.drtower_dztower * dbyz['dx'] / self.towerHt if self.precone >= 0: dtd_dprecurveTip = -dbyx['dx'] - drtower_dprecurveTip else: dtd_dprecurveTip = dbyx['dx'] - drtower_dprecurveTip dgc_dprecurveTip = dbyz['dx'] # presweep drtower_dpresweepTip = self.drtower_dztower * dbyz['dy'] / self.towerHt if self.precone >= 0: dtd_dpresweepTip = -dbyx['dy'] - drtower_dpresweepTip else: dtd_dpresweepTip = dbyx['dy'] - drtower_dpresweepTip dgc_dpresweepTip = dbyz['dy'] # precone drtower_dprecone = self.drtower_dztower * dbyz[ 'dprecone'] / self.towerHt if self.precone >= 0: dtd_dprecone = -dbyx['dprecone'] - drtower_dprecone else: dtd_dprecone = dbyx['dprecone'] - drtower_dprecone dgc_dprecone = dbyz['dprecone'] # tilt drtower_dtilt = self.drtower_dztower * dbyz['dtilt'] / self.towerHt if self.precone >= 0: dtd_dtilt = -dbyx['dtilt'] - drtower_dtilt else: dtd_dtilt = dbyx['dtilt'] - drtower_dtilt dgc_dtilt = dbyz['dtilt'] # hubtt drtower_dhubtt = self.drtower_dztower * np.array( [0.0, 0.0, 1.0 / self.towerHt]) dtd_dhubtt = np.array([-1.0, 0.0, 0.0]) - drtower_dhubtt dgc_dhubtt = np.array([0.0, 0.0, 1.0]) # tower_z dtd_dtowerz = -self.drtower_dtowerz dgc_dtowerz = np.zeros_like(self.tower_z) # tower_d dtd_dtowerd = -self.drtower_dtowerd dgc_dtowerd = np.zeros_like(self.tower_d) # towerHt drtower_dtowerHt = self.drtower_dztower * -( self.hub_tt[2] + self.blade_yaw.z) / self.towerHt**2 dtd_dtowerHt = -drtower_dtowerHt dgc_dtowerHt = 1.0 dtd = hstack([ dtd_dRtip, dtd_dprecurveTip, dtd_dpresweepTip, dtd_dprecone, dtd_dtilt, dtd_dhubtt, dtd_dtowerz, dtd_dtowerd, dtd_dtowerHt ]) dgc = np.concatenate([[dgc_dRtip], [dgc_dprecurveTip], [dgc_dpresweepTip], [dgc_dprecone], [dgc_dtilt], dgc_dhubtt, dgc_dtowerz, dgc_dtowerd, [dgc_dtowerHt]]) J = vstack([dtd, dgc]) return J
def provideJ(self): dbyx = self.blade_yaw.dx # dbyy = self.blade_yaw.dy dbyz = self.blade_yaw.dz # Rtip drtower_dRtip = self.drtower_dztower * dbyz['dz']/self.towerHt if self.precone >= 0: dtd_dRtip = -dbyx['dz'] - drtower_dRtip else: dtd_dRtip = dbyx['dz'] - drtower_dRtip dgc_dRtip = dbyz['dz'] # precurveTip drtower_dprecurveTip = self.drtower_dztower * dbyz['dx']/self.towerHt if self.precone >= 0: dtd_dprecurveTip = -dbyx['dx'] - drtower_dprecurveTip else: dtd_dprecurveTip = dbyx['dx'] - drtower_dprecurveTip dgc_dprecurveTip = dbyz['dx'] # presweep drtower_dpresweepTip = self.drtower_dztower * dbyz['dy']/self.towerHt if self.precone >= 0: dtd_dpresweepTip = -dbyx['dy'] - drtower_dpresweepTip else: dtd_dpresweepTip = dbyx['dy'] - drtower_dpresweepTip dgc_dpresweepTip = dbyz['dy'] # precone drtower_dprecone = self.drtower_dztower * dbyz['dprecone']/self.towerHt if self.precone >= 0: dtd_dprecone = -dbyx['dprecone'] - drtower_dprecone else: dtd_dprecone = dbyx['dprecone'] - drtower_dprecone dgc_dprecone = dbyz['dprecone'] # tilt drtower_dtilt = self.drtower_dztower * dbyz['dtilt']/self.towerHt if self.precone >= 0: dtd_dtilt = -dbyx['dtilt'] - drtower_dtilt else: dtd_dtilt = dbyx['dtilt'] - drtower_dtilt dgc_dtilt = dbyz['dtilt'] # hubtt drtower_dhubtt = self.drtower_dztower * np.array([0.0, 0.0, 1.0/self.towerHt]) dtd_dhubtt = np.array([-1.0, 0.0, 0.0]) - drtower_dhubtt dgc_dhubtt = np.array([0.0, 0.0, 1.0]) # tower_z dtd_dtowerz = -self.drtower_dtowerz dgc_dtowerz = np.zeros_like(self.tower_z) # tower_d dtd_dtowerd = -self.drtower_dtowerd dgc_dtowerd = np.zeros_like(self.tower_d) # towerHt drtower_dtowerHt = self.drtower_dztower * -(self.hub_tt[2] + self.blade_yaw.z)/self.towerHt**2 dtd_dtowerHt = -drtower_dtowerHt dgc_dtowerHt = 1.0 dtd = hstack([dtd_dRtip, dtd_dprecurveTip, dtd_dpresweepTip, dtd_dprecone, dtd_dtilt, dtd_dhubtt, dtd_dtowerz, dtd_dtowerd, dtd_dtowerHt]) dgc = np.concatenate([[dgc_dRtip], [dgc_dprecurveTip], [dgc_dpresweepTip], [dgc_dprecone], [dgc_dtilt], dgc_dhubtt, dgc_dtowerz, dgc_dtowerd, [dgc_dtowerHt]]) J = vstack([dtd, dgc]) return J
def evaluate(self): ctrl = self.control n = self.npts Vrated = self.Vrated # residual spline = Akima(self.Vcoarse, self.Pcoarse) P, dres_dVrated, dres_dVcoarse, dres_dPcoarse = spline.interp(Vrated) self.residual = P - ctrl.ratedPower # functional # place half of points in region 2, half in region 3 # even though region 3 is constant we still need lots of points there # because we will be integrating against a discretized wind # speed distribution # region 2 V2, _, dV2_dVrated = linspace_with_deriv(ctrl.Vin, Vrated, n/2) P2, dP2_dV2, dP2_dVcoarse, dP2_dPcoarse = spline.interp(V2) # region 3 V3, dV3_dVrated, _ = linspace_with_deriv(Vrated, ctrl.Vout, n/2+1) V3 = V3[1:] # remove duplicate point dV3_dVrated = dV3_dVrated[1:] P3 = ctrl.ratedPower*np.ones_like(V3) # concatenate self.V = np.concatenate([V2, V3]) self.P = np.concatenate([P2, P3]) # rated speed conditions Omega_d = ctrl.tsr*Vrated/self.R*RS2RPM OmegaRated, dOmegaRated_dOmegad, dOmegaRated_dmaxOmega \ = smooth_min(Omega_d, ctrl.maxOmega, pct_offset=0.01) splineT = Akima(self.Vcoarse, self.Tcoarse) Trated, dT_dVrated, dT_dVcoarse, dT_dTcoarse = splineT.interp(Vrated) self.ratedConditions.V = Vrated self.ratedConditions.Omega = OmegaRated self.ratedConditions.pitch = ctrl.pitch self.ratedConditions.T = Trated self.ratedConditions.Q = ctrl.ratedPower / (self.ratedConditions.Omega * RPM2RS) # gradients ncoarse = len(self.Vcoarse) dres = np.concatenate([[0.0], dres_dVcoarse, dres_dPcoarse, np.zeros(ncoarse), np.array([dres_dVrated]), [0.0, 0.0]]) dV_dVrated = np.concatenate([dV2_dVrated, dV3_dVrated]) dV = hstack([np.zeros((n, 1)), np.zeros((n, 3*ncoarse)), dV_dVrated, np.zeros((n, 2))]) dP_dVcoarse = vstack([dP2_dVcoarse, np.zeros((n/2, ncoarse))]) dP_dPcoarse = vstack([dP2_dPcoarse, np.zeros((n/2, ncoarse))]) dP_dVrated = np.concatenate([dP2_dV2*dV2_dVrated, np.zeros(n/2)]) dP = hstack([np.zeros((n, 1)), dP_dVcoarse, dP_dPcoarse, np.zeros((n, ncoarse)), dP_dVrated, np.zeros((n, 2))]) drV = np.concatenate([[0.0], np.zeros(3*ncoarse), [1.0, 0.0, 0.0]]) drOmega = np.concatenate([[dOmegaRated_dOmegad*Vrated/self.R*RS2RPM], np.zeros(3*ncoarse), [dOmegaRated_dOmegad*ctrl.tsr/self.R*RS2RPM, -dOmegaRated_dOmegad*ctrl.tsr*Vrated/self.R**2*RS2RPM, dOmegaRated_dmaxOmega]]) drpitch = np.zeros(3*ncoarse+4) drT = np.concatenate([[0.0], dT_dVcoarse, np.zeros(ncoarse), dT_dTcoarse, [dT_dVrated, 0.0, 0.0]]) drQ = -ctrl.ratedPower / (self.ratedConditions.Omega**2 * RPM2RS) * drOmega self.J = vstack([dres, dV, dP, drV, drOmega, drpitch, drT, drQ])
def provideJ(self): if self.run_case == 'power': dP = self.dP dT = self.dT dQ = self.dQ jP = hstack([ dP['dprecone'], dP['dtilt'], dP['dhubHt'], dP['dRhub'], dP['dRtip'], dP['dyaw'], dP['dUinf'], dP['dOmega'], dP['dpitch'], dP['dr'], dP['dchord'], dP['dtheta'], dP['dprecurve'], dP['dprecurveTip'] ]) jT = hstack([ dT['dprecone'], dT['dtilt'], dT['dhubHt'], dT['dRhub'], dT['dRtip'], dT['dyaw'], dT['dUinf'], dT['dOmega'], dT['dpitch'], dT['dr'], dT['dchord'], dT['dtheta'], dT['dprecurve'], dT['dprecurveTip'] ]) jQ = hstack([ dQ['dprecone'], dQ['dtilt'], dQ['dhubHt'], dQ['dRhub'], dQ['dRtip'], dQ['dyaw'], dQ['dUinf'], dQ['dOmega'], dQ['dpitch'], dQ['dr'], dQ['dchord'], dQ['dtheta'], dQ['dprecurve'], dQ['dprecurveTip'] ]) J = vstack([jP, jT, jQ]) elif self.run_case == 'loads': dNp = self.dNp dTp = self.dTp n = len(self.r) dr_dr = vstack([np.zeros(n), np.eye(n), np.zeros(n)]) dr_dRhub = np.zeros(n + 2) dr_dRtip = np.zeros(n + 2) dr_dRhub[0] = 1.0 dr_dRtip[-1] = 1.0 dr = hstack([ dr_dr, np.zeros((n + 2, 2 * n)), dr_dRhub, dr_dRtip, np.zeros((n + 2, 8 + n)) ]) jNp = hstack([ dNp['dr'], dNp['dchord'], dNp['dtheta'], dNp['dRhub'], dNp['dRtip'], dNp['dhubHt'], dNp['dprecone'], dNp['dtilt'], dNp['dyaw'], dNp['dUinf'], dNp['dOmega'], dNp['dpitch'], dNp['dazimuth'], dNp['dprecurve'] ]) jTp = hstack([ dTp['dr'], dTp['dchord'], dTp['dtheta'], dTp['dRhub'], dTp['dRtip'], dTp['dhubHt'], dTp['dprecone'], dTp['dtilt'], dTp['dyaw'], dTp['dUinf'], dTp['dOmega'], dTp['dpitch'], dTp['dazimuth'], dTp['dprecurve'] ]) dPx = vstack([np.zeros(4 * n + 10), jNp, np.zeros(4 * n + 10)]) dPy = vstack([np.zeros(4 * n + 10), -jTp, np.zeros(4 * n + 10)]) dPz = np.zeros((n + 2, 4 * n + 10)) dV = np.zeros(4 * n + 10) dV[3 * n + 6] = 1.0 dOmega = np.zeros(4 * n + 10) dOmega[3 * n + 7] = 1.0 dpitch = np.zeros(4 * n + 10) dpitch[3 * n + 8] = 1.0 dazimuth = np.zeros(4 * n + 10) dazimuth[3 * n + 9] = 1.0 J = vstack([dr, dPx, dPy, dPz, dV, dOmega, dpitch, dazimuth]) return J
def linearize(self, params, unknowns, resids): dF = DirectionVector.fromArray(params['F']).hubToYaw(params['tilt']) dFx, dFy, dFz = dF.dx, dF.dy, dF.dz dtopF_dFx = np.array([dFx['dx'], dFy['dx'], dFz['dx']]) dtopF_dFy = np.array([dFx['dy'], dFy['dy'], dFz['dy']]) dtopF_dFz = np.array([dFx['dz'], dFy['dz'], dFz['dz']]) dtopF_dF = hstack([dtopF_dFx, dtopF_dFy, dtopF_dFz]) dtopF_w_dm = np.array([0.0, 0.0, -self.g]) #dtopF = hstack([dtopF_dF, np.zeros((3, 6)), dtopF_w_dm, np.zeros((3, 3))]) dM = DirectionVector.fromArray(params['M']).hubToYaw(params['tilt']) dMx, dMy, dMz = dM.dx, dM.dy, dM.dz dMxcross, dMycross, dMzcross = self.save_rhub.cross_deriv( self.saveF, 'dr', 'dF') dtopM_dMx = np.array([dMx['dx'], dMy['dx'], dMz['dx']]) dtopM_dMy = np.array([dMx['dy'], dMy['dy'], dMz['dy']]) dtopM_dMz = np.array([dMx['dz'], dMy['dz'], dMz['dz']]) dtopM_dM = hstack([dtopM_dMx, dtopM_dMy, dtopM_dMz]) dM_dF = np.array([dMxcross['dF'], dMycross['dF'], dMzcross['dF']]) dtopM_dFx = np.dot(dM_dF, dtopF_dFx) dtopM_dFy = np.dot(dM_dF, dtopF_dFy) dtopM_dFz = np.dot(dM_dF, dtopF_dFz) dtopM_dF = hstack([dtopM_dFx, dtopM_dFy, dtopM_dFz]) dtopM_dr = np.array([dMxcross['dr'], dMycross['dr'], dMzcross['dr']]) dMx_w_cross, dMy_w_cross, dMz_w_cross = self.save_rcm.cross_deriv( self.saveF_w, 'dr', 'dF') if params['rna_weightM']: dtopM_drnacm = np.array( [dMx_w_cross['dr'], dMy_w_cross['dr'], dMz_w_cross['dr']]) dtopM_dF_w = np.array( [dMx_w_cross['dF'], dMy_w_cross['dF'], dMz_w_cross['dF']]) else: dtopM_drnacm = np.zeros((3, 3)) dtopM_dF_w = np.zeros((3, 3)) dtopM_dm = np.dot(dtopM_dF_w, dtopF_w_dm) if params['downwind']: dtopM_dr[:, 0] *= -1 dtopM_drnacm[:, 0] *= -1 #dtopM = hstack([dtopM_dF, dtopM_dM, dtopM_dr, dtopM_dm, dtopM_drnacm]) J = {} J['top_F', 'F'] = dtopF_dF J['top_F', 'M'] = np.zeros((3, 3)) J['top_F', 'r_hub'] = np.zeros((3, 3)) J['top_F', 'rna_mass'] = dtopF_w_dm J['top_F', 'rna_cm'] = np.zeros((3, 3)) J['top_M', 'F'] = dtopM_dF J['top_M', 'M'] = dtopM_dM J['top_M', 'r_hub'] = dtopM_dr J['top_M', 'rna_mass'] = dtopM_dm J['top_M', 'rna_cm'] = dtopM_drnacm return J
def execute(self): nc = len(self.chord_sub) nt = len(self.theta_sub) Rhub = self.Rhub Rtip = self.Rtip idxc = self.idx_cylinder r_max_chord = Rhub + (Rtip - Rhub) * self.r_max_chord r_cylinder = Rhub + (Rtip - Rhub) * self.r_af[idxc] # chord parameterization rc_outer, drc_drcmax, drc_drtip = linspace_with_deriv( r_max_chord, Rtip, nc - 1) r_chord = np.concatenate([[Rhub], rc_outer]) drc_drcmax = np.concatenate([[0.0], drc_drcmax]) drc_drtip = np.concatenate([[0.0], drc_drtip]) drc_drhub = np.concatenate([[1.0], np.zeros(nc - 1)]) # theta parameterization r_theta, drt_drcyl, drt_drtip = linspace_with_deriv( r_cylinder, Rtip, nt) # spline chord_spline = Akima(r_chord, self.chord_sub) theta_spline = Akima(r_theta, self.theta_sub) self.r = Rhub + (Rtip - Rhub) * self.r_af self.chord, dchord_dr, dchord_drchord, dchord_dchordsub = chord_spline.interp( self.r) theta_outer, dthetaouter_dr, dthetaouter_drtheta, dthetaouter_dthetasub = theta_spline.interp( self.r[idxc:]) theta_inner = theta_outer[0] * np.ones(idxc) self.theta = np.concatenate([theta_inner, theta_outer]) self.r_af_spacing = np.diff(self.r_af) self.precurve = np.zeros_like( self.chord ) # TODO: for now I'm forcing this to zero, just for backwards compatibility # gradients (TODO: rethink these a bit or use Tapenade.) n = len(self.r_af) dr_draf = (Rtip - Rhub) * np.ones(n) dr_dRhub = 1.0 - self.r_af dr_dRtip = self.r_af dr = hstack([ np.diag(dr_draf), np.zeros((n, 1)), dr_dRhub, dr_dRtip, np.zeros((n, nc + nt)) ]) dchord_draf = dchord_dr * dr_draf dchord_drmaxchord0 = np.dot(dchord_drchord, drc_drcmax) dchord_drmaxchord = dchord_drmaxchord0 * (Rtip - Rhub) dchord_drhub = np.dot( dchord_drchord, drc_drhub) + dchord_drmaxchord0 * ( 1.0 - self.r_max_chord) + dchord_dr * dr_dRhub dchord_drtip = np.dot(dchord_drchord, drc_drtip) + dchord_drmaxchord0 * ( self.r_max_chord) + dchord_dr * dr_dRtip dchord = hstack([ np.diag(dchord_draf), dchord_drmaxchord, dchord_drhub, dchord_drtip, dchord_dchordsub, np.zeros((n, nt)) ]) dthetaouter_dcyl = np.dot(dthetaouter_drtheta, drt_drcyl) dthetaouter_draf = dthetaouter_dr * dr_draf[idxc:] dthetaouter_drhub = dthetaouter_dr * dr_dRhub[idxc:] dthetaouter_drtip = dthetaouter_dr * dr_dRtip[idxc:] + np.dot( dthetaouter_drtheta, drt_drtip) dtheta_draf = np.concatenate([np.zeros(idxc), dthetaouter_draf]) dtheta_drhub = np.concatenate( [dthetaouter_drhub[0] * np.ones(idxc), dthetaouter_drhub]) dtheta_drtip = np.concatenate( [dthetaouter_drtip[0] * np.ones(idxc), dthetaouter_drtip]) sub = dthetaouter_dthetasub[0, :] dtheta_dthetasub = vstack([ np.dot(np.ones((idxc, 1)), sub[np.newaxis, :]), dthetaouter_dthetasub ]) dtheta_draf = np.diag(dtheta_draf) dtheta_dcyl = np.concatenate( [dthetaouter_dcyl[0] * np.ones(idxc), dthetaouter_dcyl]) dtheta_draf[idxc:, idxc] += dthetaouter_dcyl * (Rtip - Rhub) dtheta_drhub += dtheta_dcyl * (1.0 - self.r_af[idxc]) dtheta_drtip += dtheta_dcyl * self.r_af[idxc] dtheta = hstack([ dtheta_draf, np.zeros((n, 1)), dtheta_drhub, dtheta_drtip, np.zeros((n, nc)), dtheta_dthetasub ]) drafs_dr = np.zeros((n - 1, n)) for i in range(n - 1): drafs_dr[i, i] = -1.0 drafs_dr[i, i + 1] = 1.0 drafs = hstack([drafs_dr, np.zeros((n - 1, 3 + nc + nt))]) dprecurve = np.zeros((len(self.precurve), n + 3 + nc + nt)) self.J = vstack([dr, dchord, dtheta, drafs, dprecurve])