ispodfL = [] # list of IspODF (frozen) mrcoreL = [] # list of MRcore (core stream tube mixture ratio) for MRcore in np.linspace(mr_lo, mr_hi, num=60): C.reset_attr('MRcore', MRcore) R.scale_Rt_to_Thrust(Fvac, Pamb=0.0) ispodeL.append(C('IspODE')) ispodkL.append(C('IspODK')) ispodfL.append(C('IspODF')) mrcoreL.append(C('MRcore')) # ======================================================== # ======= find peaks ====== mr_ode_terp = InterpProp(mrcoreL, ispodeL) mr_ode_Peak, isp_ode_peak = gold_search_max(mr_ode_terp, mrcoreL[0], mrcoreL[-1], tol=1.0e-5) isp_ode_peak = -isp_ode_peak print('mr_ode_Peak, isp_ode_peak', mr_ode_Peak, isp_ode_peak) mr_odk_terp = InterpProp(mrcoreL, ispodkL) mr_odk_Peak, isp_odk_peak = gold_search_max(mr_odk_terp, mrcoreL[0], mrcoreL[-1], tol=1.0e-5) isp_odk_peak = -isp_odk_peak print('mr_odk_Peak, isp_odk_peak', mr_odk_Peak, isp_odk_peak) mr_odf_terp = InterpProp(mrcoreL, ispodfL) mr_odf_Peak, isp_odf_peak = gold_search_max(mr_odf_terp, mrcoreL[0],
def calc_ODE_ODK_FROZ_isp(oxName='N2O4', fuelName='MMH', Pc=1000.0, eps=10.0, pcentBell=80.0, Fvac=1000.0, NumRuns=20, do_show=True): # ============ use RocketCEA to find MR range =================== mc = MR_Temperature_Limits(oxName=oxName, fuelName=fuelName, PcNominal=Pc, epsNominal=eps) mr_peak = MR_Peak_At_EpsPc( mc, pc=Pc, eps=eps, ispType='CEAODE', # ispType can be CEAODE, CEAFROZEN NterpSize=100) print('Peak IspODE=%g sec at MR =' % mr_peak.ispPeak, mr_peak.mrPeak) print() print('MR at 97% Isp (on low side) =', mr_peak.calc_mrLow_minus_NPcentIsp()) print('MR at 97% Isp (on high side) =', mr_peak.calc_mrHigh_minus_NPcentIsp()) mr_lo = round( mr_peak.mrLeftOfPeak - (mr_peak.mrRightOfPeak - mr_peak.mrLeftOfPeak) / 10.0, 2) mr_hi = round(mr_peak.mrRightOfPeak, 2) delMR = (mr_hi - mr_lo) / (NumRuns - 1) # =============================== geomObj = Geometry(Rthrt=5.868 / 2, CR=2.5, eps=eps, pcentBell=pcentBell, RupThroat=1.5, RdwnThroat=1.0, RchmConv=1.0, cham_conv_deg=30, LchmOvrDt=3.10, LchmMin=2.0, LchamberInp=16) core = CoreStream(geomObj, oxName=oxName, fuelName=fuelName, MRcore=1.6, Pc=Pc) R = RocketThruster(name='sample', coreObj=core, injObj=None) ispodeL = [] ispodkL = [] ispodfL = [] mrL = [] MR = mr_lo for _ in range(NumRuns): mrL.append(MR) core.reset_attr('MRcore', MR, re_evaluate=True) R.scale_Rt_to_Thrust(Fvac, Pamb=0.0, use_scipy=False) ispodeL.append(R.coreObj.IspODE) ispodkL.append(R.coreObj.IspODK) ispodfL.append(R.coreObj.IspODF) MR += delMR # ======= find peaks ====== mr_ode_terp = InterpProp(mrL, ispodeL) mr_ode_Peak, isp_ode_peak = gold_search_max(mr_ode_terp, mrL[0], mrL[-1], tol=1.0e-5) mr_odk_terp = InterpProp(mrL, ispodkL) mr_odk_Peak, isp_odk_peak = gold_search_max(mr_odk_terp, mrL[0], mrL[-1], tol=1.0e-5) mr_odf_terp = InterpProp(mrL, ispodfL) mr_odf_Peak, isp_odf_peak = gold_search_max(mr_odf_terp, mrL[0], mrL[-1], tol=1.0e-5) fig, ax = plt.subplots(figsize=(8, 6)) plt.plot(mrL, ispodeL, label='IspODE', color=COLORL[0]) plt.plot(mrL, ispodkL, label='IspODK', color=COLORL[1]) plt.plot(mrL, ispodfL, label='IspODF', color=COLORL[2]) # show ========= optimum MR difference ======== def span_mrpeak(isL): minpt = min(isL) maxpt = max(isL) span = maxpt - minpt return [maxpt - 0.8 * span, maxpt] plt.plot([mr_ode_Peak, mr_ode_Peak], span_mrpeak(ispodeL), '--', label='MRode=%.2f' % mr_ode_Peak, linewidth=2, color=COLORL[0]) plt.plot([mr_odk_Peak, mr_odk_Peak], span_mrpeak(ispodkL), '--', label='MRodk=%.2f' % mr_odk_Peak, linewidth=2, color=COLORL[1]) plt.plot([mr_odf_Peak, mr_odf_Peak], span_mrpeak(ispodfL), '--', label='MRodf=%.2f' % mr_odf_Peak, linewidth=2, color=COLORL[2]) isp_odk_peak = abs(isp_odk_peak) plt.text(mr_odk_Peak, isp_odk_peak, '%i' % int(isp_odk_peak), ha='left', va='bottom', transform=ax.transData, color=COLORL[1]) plt.legend() plt.ylabel('Isp (sec)') plt.xlabel('Mixture Ratio') plt.title( "%s/%s RocketIsp ODE ODK ODF\nFvac=%.0f lbf, Pc=%.0f psia, AR=%.0f:1, %%Bell=%.0f%%"%\ (oxName, fuelName, Fvac, Pc, eps, pcentBell)) png_name = 'odekf_%s_%s_Fvac%g_Pc%g_eps%g.png' % (oxName, fuelName, Fvac, Pc, eps) plt.savefig(png_name, dpi=120) if do_show: plt.show()
def __init__( self, mrLimitsObj, pc=100., eps=10., ispType='CEAODE', # ispType can be CEAODE, CEAFROZEN NterpSize=100): # size of interpolation array self.mrLimitsObj = mrLimitsObj self.pc = pc self.eps = eps self.ispType = ispType self.mrL = [ ] # build lists of non-zero isp both above and below stoich_MR self.isL = [] stoich_MR = self.mrLimitsObj.Stoich_MR #print( 'stoich_MR =',stoich_MR) stoich_fox = frac_ox(stoich_MR) #print( 'stoich_fox =',stoich_fox) self.stoich_fox = stoich_fox stoich_Isp = self.isp_at_mr(mr=stoich_MR) # build mr and isp lists from the stoich point to the left and right. # Only bother doing this because CEA frozen calc will often fail with condensed species. # build list from stoich towards MR=0 mr_leftL = [stoich_MR] is_leftL = [stoich_Isp] df = 1.0 / float(NterpSize) fox = stoich_fox - df while fox > 0.0: mr = mr_of_fracox(fox) isp = self.isp_at_mr(mr=mr) if isp > 1.0: mr_leftL.append(mr) is_leftL.append(isp) fox = fox - df if isp < stoich_Isp * 0.9: break else: break #print 'mr_leftL =',mr_leftL #print 'is_leftL =',is_leftL # build list from stoich towards ox fraction = 1.0 mr_rightL = [] is_rightL = [] fox = stoich_fox + df while fox < 1.0: mr = mr_of_fracox(fox) isp = self.isp_at_mr(mr=mr) if isp > 1.0: mr_rightL.append(mr) is_rightL.append(isp) fox = fox + df if isp < stoich_Isp * 0.9: break else: break #print 'mr_rightL =',mr_rightL #print 'is_rightL =',is_rightL # combine both lists mr_leftL.reverse() is_leftL.reverse() self.mrL = mr_leftL + mr_rightL self.isL = is_leftL + is_rightL if len(self.mrL) < 3: print('ERROR... len(mrL) < 3') #print 'Optimizing pc=%g, eps=%g'%(pc, eps) self.mr_isp_terp = InterpProp(self.mrL, self.isL) self.mrPeak, iterp_peak = gold_search_max(self.mr_isp_terp, self.mrL[0], self.mrL[-1], tol=1.0e-5) self.ispPeak = self.isp_at_mr(mr=self.mrPeak) self.isp_min = min(self.isL) self.isp_max = max(self.isL) if self.ispPeak < 0.01 or self.mrPeak < 0.0: imin = 0 for i in range(len(self.mrL)): if self.isL[i] < self.isL[imin]: imin = i imax = min(len(self.mrL) - 1, imin + 2) imin = max(0, imin - 2) self.mrPeak, iterp_peak = gold_search_max(self.mr_isp_terp, self.mrL[imin], self.mrL[imax], tol=1.0e-5) self.ispPeak = self.isp_at_mr(mr=self.mrPeak) if self.ispPeak < 0.01 or self.mrPeak < 0.0: print(( '_______________BAD OPTIMUM at pc=%g and eps=%g mrPeak=%g, ispPeak=%g' % (pc, eps, self.ispPeak, self.mrPeak))) # place holders for left and right of peak Isp self._mrLeftOfPeak = None self._mrRightOfPeak = None