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 solve_nonlinear(self, params, unknowns, resids): n = params['npts'] # finer power curve V, _, _ = linspace_with_deriv(params['control:Vin'], params['control:Vout'], n) unknowns['V'] = V spline = Akima(params['Vcoarse'], params['Pcoarse']) P, dP_dV, dP_dVcoarse, dP_dPcoarse = spline.interp(unknowns['V']) unknowns['P'] = P J = {} J['P', 'Vcoarse'] = dP_dVcoarse J['P', 'Pcoarse'] = dP_dPcoarse self.J = 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 apply_nonlinear(self, params, unknowns, resids): n = params['npts'] Vrated = unknowns['Vrated'] # residual spline = Akima(params['Vcoarse'], params['Pcoarse']) P, dres_dVrated, dres_dVcoarse, dres_dPcoarse = spline.interp(Vrated) resids['Vrated'] = P - params['control:ratedPower'] if True: P1, _, _, _ = spline.interp(params['control:Vin']) P2, _, _, _ = spline.interp(params['control:Vout']) resids1 = P1 - params['control:ratedPower'] resids2 = P2 - params['control:ratedPower'] if ((resids1 < 0) == (resids2 < 0)): if Vrated == params['control:Vout']: resids['Vrated'] = 10000 elif Vrated != params['control:Vin']: resids['Vrated'] = 0 ## Test on # region 2 V2, _, dV2_dVrated = linspace_with_deriv(params['control:Vin'], Vrated, n / 2) P2, dP2_dV2, dP2_dVcoarse, dP2_dPcoarse = spline.interp(V2) # region 3 V3, dV3_dVrated, _ = linspace_with_deriv(Vrated, params['control:Vout'], n / 2 + 1) V3 = V3[1:] # remove duplicate point dV3_dVrated = dV3_dVrated[1:] P3 = params['control:ratedPower'] * np.ones_like(V3) # concatenate unknowns['V'] = np.concatenate([V2, V3]) unknowns['P'] = np.concatenate([P2, P3]) R = params['R'] # rated speed conditions Omega_d = params['control:tsr'] * Vrated / R * RS2RPM OmegaRated, dOmegaRated_dOmegad, dOmegaRated_dmaxOmega \ = smooth_min(Omega_d, params['control:maxOmega'], pct_offset=0.01) splineT = Akima(params['Vcoarse'], params['Tcoarse']) Trated, dT_dVrated, dT_dVcoarse, dT_dTcoarse = splineT.interp(Vrated) unknowns['ratedConditions:V'] = Vrated unknowns['ratedConditions:Omega'] = OmegaRated unknowns['ratedConditions:pitch'] = params['control:pitch'] unknowns['ratedConditions:T'] = Trated unknowns['ratedConditions:Q'] = params['control:ratedPower'] / ( OmegaRated * RPM2RS) unknowns['azimuth'] = 180.0 # gradients ncoarse = len(params['Vcoarse']) dV_dVrated = np.concatenate([dV2_dVrated, dV3_dVrated]) 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)]) drOmega = np.concatenate( [[dOmegaRated_dOmegad * Vrated / R * RS2RPM], np.zeros(3 * ncoarse), [ dOmegaRated_dOmegad * params['control:tsr'] / R * RS2RPM, -dOmegaRated_dOmegad * params['control:tsr'] * Vrated / R**2 * RS2RPM, dOmegaRated_dmaxOmega ]]) drQ = -params['control:ratedPower'] / (OmegaRated**2 * RPM2RS) * drOmega J = {} J['Vrated', 'Vcoarse'] = np.reshape(dres_dVcoarse, (1, len(dres_dVcoarse))) J['Vrated', 'Pcoarse'] = np.reshape(dres_dPcoarse, (1, len(dres_dPcoarse))) J['Vrated', 'Vrated'] = dres_dVrated J['V', 'Vrated'] = dV_dVrated J['P', 'Vrated'] = dP_dVrated J['P', 'Vcoarse'] = dP_dVcoarse J['P', 'Pcoarse'] = dP_dPcoarse J['ratedConditions:V', 'Vrated'] = 1.0 J['ratedConditions:Omega', 'control:tsr'] = dOmegaRated_dOmegad * Vrated / R * RS2RPM J['ratedConditions:Omega', 'Vrated'] = dOmegaRated_dOmegad * params['control:tsr'] / R * RS2RPM J['ratedConditions:Omega', 'R'] = -dOmegaRated_dOmegad * params[ 'control:tsr'] * Vrated / R**2 * RS2RPM J['ratedConditions:Omega', 'control:maxOmega'] = dOmegaRated_dmaxOmega J['ratedConditions:T', 'Vcoarse'] = np.reshape(dT_dVcoarse, (1, len(dT_dVcoarse))) J['ratedConditions:T', 'Tcoarse'] = np.reshape(dT_dTcoarse, (1, len(dT_dTcoarse))) J['ratedConditions:T', 'Vrated'] = dT_dVrated J['ratedConditions:Q', 'control:tsr'] = drQ[0] J['ratedConditions:Q', 'Vrated'] = drQ[-3] J['ratedConditions:Q', 'R'] = drQ[-2] J['ratedConditions:Q', 'control:maxOmega'] = drQ[-1] self.J = 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 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])