def TurbofanNacelle(EngineSection, Chord, CentreLocation=[0, 0, 0], ScarfAngle=3, HighlightRadius=1.45, MeanNacelleLength=5.67): # The defaults yield a nacelle similar to that of an RR Trent 1000 / GEnx HighlightDepth = 0.12 * MeanNacelleLength SectionNo = 100 # Draw the nacelle with the centre of the intake highlight circle in 0,0,0 rs.EnableRedraw(False) Highlight = rs.AddCircle3Pt((0, 0, HighlightRadius), (0, -HighlightRadius, 0), (0, 0, -HighlightRadius)) HighlightCutterCircle = rs.AddCircle3Pt((0, 0, HighlightRadius * 1.5), (0, -HighlightRadius * 1.5, 0), (0, 0, -HighlightRadius * 1.5)) # Fan disk for CFD boundary conditions FanCircle = rs.CopyObject(Highlight, (MeanNacelleLength * 0.25, 0, 0)) FanDisk = rs.AddPlanarSrf(FanCircle) # Aft outflow for CFD boundary conditions BypassCircle = rs.CopyObject(Highlight, (MeanNacelleLength * 0.85, 0, 0)) BypassDisk = rs.AddPlanarSrf(BypassCircle) rs.DeleteObjects([FanCircle, BypassCircle]) # Outflow cone TailConeBasePoint = [MeanNacelleLength * 0.84, 0, 0] TailConeApex = [MeanNacelleLength * 1.35, 0, 0] TailConeRadius = HighlightRadius * 0.782 TailCone = rs.AddCone(TailConeBasePoint, TailConeApex, TailConeRadius) # Spinner cone SpinnerConeBasePoint = [MeanNacelleLength * 0.26, 0, 0] SpinnerConeApex = [MeanNacelleLength * 0.08, 0, 0] SpinnerConeRadius = MeanNacelleLength * 0.09 Spinner = rs.AddCone(SpinnerConeBasePoint, SpinnerConeApex, SpinnerConeRadius) # Tilt the intake RotVec = rs.VectorCreate((0, 0, 0), (0, 1, 0)) Highlight = rs.RotateObject(Highlight, (0, 0, 0), ScarfAngle, axis=RotVec) # Set up the disk for separating the intake lip later HighlightCutterCircle = rs.RotateObject(HighlightCutterCircle, (0, 0, 0), ScarfAngle, axis=RotVec) HighlightCutterDisk = rs.AddPlanarSrf(HighlightCutterCircle) rs.DeleteObject(HighlightCutterCircle) rs.MoveObject(HighlightCutterDisk, (HighlightDepth, 0, 0)) # Build the actual airfoil sections to define the nacelle HighlightPointVector = rs.DivideCurve(Highlight, SectionNo) Sections = [] TailPoints = [] Rotation = 0 Twist = 0 AirfoilSeligName = 'goe613' SmoothingPasses = 1 for HighlightPoint in HighlightPointVector: ChordLength = MeanNacelleLength - HighlightPoint.X Af = primitives.Airfoil(HighlightPoint, ChordLength, Rotation, Twist, airconics_setup.SeligPath) AfCurve, Chrd = primitives.Airfoil.AddAirfoilFromSeligFile( Af, AirfoilSeligName, SmoothingPasses) rs.DeleteObject(Chrd) P = rs.CurveEndPoint(AfCurve) list.append(TailPoints, P) AfCurve = act.AddTEtoOpenAirfoil(AfCurve) list.append(Sections, AfCurve) Rotation = Rotation + 360.0 / SectionNo list.append(TailPoints, TailPoints[0]) # Build the actual nacelle OML surface EndCircle = rs.AddInterpCurve(TailPoints) Nacelle = rs.AddSweep2([Highlight, EndCircle], Sections, closed=True) # Separate the lip Cowling, HighlightSection = rs.SplitBrep(Nacelle, HighlightCutterDisk, True) # Now build the pylon between the engine and the specified chord on the wing CP1 = [ MeanNacelleLength * 0.26 + CentreLocation[0], CentreLocation[1], CentreLocation[2] + HighlightRadius * 0.1 ] CP2 = [ MeanNacelleLength * 0.4 + CentreLocation[0], CentreLocation[1], HighlightRadius * 1.45 + CentreLocation[2] ] CP3 = rs.CurveEndPoint(Chord) rs.ReverseCurve(Chord) CP4 = rs.CurveEndPoint(Chord) # Move the engine into its actual place on the wing rs.MoveObjects( [HighlightSection, Cowling, FanDisk, BypassDisk, TailCone, Spinner], CentreLocation) # Pylon wireframe PylonTop = rs.AddInterpCurve([CP1, CP2, CP3, CP4]) PylonAf = primitives.Airfoil(CP1, MeanNacelleLength * 1.35, 90, 0, airconics_setup.SeligPath) PylonAfCurve, PylonChord = primitives.Airfoil.AddNACA4( PylonAf, 0, 0, 12, 3) LowerTE = rs.CurveEndPoint(PylonChord) PylonTE = rs.AddLine(LowerTE, CP4) # Create the actual pylon surface PylonLeft = rs.AddNetworkSrf([PylonTop, PylonAfCurve, PylonTE]) rs.MoveObject(PylonLeft, (0, -CentreLocation[1], 0)) PylonRight = act.MirrorObjectXZ(PylonLeft) rs.MoveObject(PylonLeft, (0, CentreLocation[1], 0)) rs.MoveObject(PylonRight, (0, CentreLocation[1], 0)) PylonAfCurve = act.AddTEtoOpenAirfoil(PylonAfCurve) PylonAfSrf = rs.AddPlanarSrf(PylonAfCurve) # Assigning basic surface properties act.AssignMaterial(Cowling, "ShinyBABlueMetal") act.AssignMaterial(HighlightSection, "UnpaintedMetal") act.AssignMaterial(TailCone, "UnpaintedMetal") act.AssignMaterial(FanDisk, "FanDisk") act.AssignMaterial(Spinner, "ShinyBlack") act.AssignMaterial(BypassDisk, "FanDisk") act.AssignMaterial(PylonLeft, "White_composite_external") act.AssignMaterial(PylonRight, "White_composite_external") # Clean-up rs.DeleteObject(HighlightCutterDisk) rs.DeleteObjects(Sections) rs.DeleteObject(EndCircle) rs.DeleteObject(Highlight) rs.DeleteObjects([PylonTop, PylonAfCurve, PylonChord, PylonTE]) rs.Redraw() TFEngine = [ Cowling, HighlightSection, TailCone, FanDisk, Spinner, BypassDisk ] TFPylon = [PylonLeft, PylonRight, PylonAfSrf] return TFEngine, TFPylon
def _BuildLS(self, ChordFactor, ScaleFactor): # Generates a tentative lifting surface, given the general, nondimensio- # nal parameters of the object (variations of chord length, dihedral, etc.) # and the two scaling factors. LEPoints = self._GenerateLeadingEdge() Sections = [] ProjectedSections = [] TEPoints_u = [] TEPoints_l = [] for i, LEP in enumerate(LEPoints): Eps = float(i)/self.SegmentNo Airfoil, Chrd = self.AirfoilFunct(Eps, LEP, self.ChordFunct, ChordFactor, self.DihedralFunct, self.TwistFunct) list.append(Sections, Airfoil) Pr = rs.ProjectCurveToSurface(Chrd,self.XoY_Plane,self.ProjVectorZ) list.append(ProjectedSections, Pr) list.append(TEPoints_l, rs.CurveEndPoint(Airfoil)) list.append(TEPoints_u, rs.CurveStartPoint(Airfoil)) rs.DeleteObjects(Chrd) LS = rs.AddLoftSrf(Sections,loft_type=self.LooseSurf) if LS==None: # Failed to fit loft surface. Try another fitting algorithm TECurve_u = rs.AddInterpCurve(TEPoints_u) TECurve_l = rs.AddInterpCurve(TEPoints_l) rails = [] list.append(rails, TECurve_u) list.append(rails, TECurve_l) # Are the first and last curves identical? # AddSweep fails if they are, so if that is the case, one is skipped CDev = rs.CurveDeviation(Sections[0],Sections[-1]) if CDev==None: shapes = Sections LS = rs.AddSweep2(rails, shapes, False) else: shapes = Sections[:-1] LS = rs.AddSweep2(rails, shapes, True) rs.DeleteObjects(rails) rs.DeleteObjects([TECurve_u, TECurve_l]) WingTip = None if self.TipRequired: TipCurve = Sections[-1] TipCurve = act.AddTEtoOpenAirfoil(TipCurve) WingTip = rs.AddPlanarSrf(TipCurve) rs.DeleteObject(TipCurve) # Calculate projected area # In some cases the projected sections cannot all be lofted in one go # (it happens when parts of the wing fold back onto themselves), so # we loft them section by section and we compute the area as a sum. LSP_area = 0 # Attempt to compute a projected area try: for i, LEP in enumerate(ProjectedSections): if i < len(ProjectedSections)-1: LSPsegment = rs.AddLoftSrf(ProjectedSections[i:i+2]) SA = rs.SurfaceArea(LSPsegment) rs.DeleteObject(LSPsegment) LSP_area = LSP_area + SA[0] except: print "Failed to compute projected area. Using half of surface area instead." LS_area = rs.SurfaceArea(LS) LSP_area = 0.5*LS_area[0] BB = rs.BoundingBox(LS) if BB: ActualSemiSpan = BB[2].Y - BB[0].Y else: ActualSemiSpan = 0.0 # Garbage collection rs.DeleteObjects(Sections) try: rs.DeleteObjects(ProjectedSections) except: print "Cleanup: no projected sections to delete" rs.DeleteObjects(LEPoints) # Scaling Origin = rs.AddPoint([0,0,0]) ScaleXYZ = (ScaleFactor, ScaleFactor, ScaleFactor) LS = rs.ScaleObject(LS, Origin, ScaleXYZ) if self.TipRequired and WingTip: WingTip = rs.ScaleObject(WingTip, Origin, ScaleXYZ) rs.DeleteObject(Origin) ActualSemiSpan = ActualSemiSpan*ScaleFactor LSP_area = LSP_area*ScaleFactor**2.0 RootChord = (self.ChordFunct(0)*ChordFactor)*ScaleFactor AR = ((2.0*ActualSemiSpan)**2.0)/(2*LSP_area) return LS, ActualSemiSpan, LSP_area, RootChord, AR, WingTip