def Run_Cpp_Solver_VLM(VMOPTS, VMINPUT, VMUNST=None, AELOPTS=None): # init grid if VMUNST == None: # Set up variables assuming no unsteady motion VMUNST = MyStruct() VMUNST.PsiA_G = np.array([0.0, 0.0, 0.0]) VMUNST.VelA_G = np.array([0.0, 0.0, 0.0]) VMUNST.OmegaA_G = np.array([0.0, 0.0, 0.0]) VMUNST.OriginA_G = np.array([0.0, 0.0, 0.0]) if AELOPTS == None: # Set up defaults for grid generation. AELOPTS = MyStruct() AELOPTS.ElasticAxis = 0.0 # Initialise DerivedTypes for PyBeam initialization. XBOPTS = DerivedTypes.Xbopts() XBINPUT = DerivedTypes.Xbinput(2, VMOPTS.N.value, VMINPUT.b) # Create a dummy stiffness matrix to avoid errors. XBINPUT.BeamStiffness = np.eye(6, dtype=ct.c_double) # Use PyBeam to define reference beam (elastic axis). XBINPUT, XBOPTS, NumNodes_tot, XBELEM, PosIni, PsiIni,\ XBNODE, NumDof = BeamInit.Static(XBINPUT, XBOPTS) # Delete unnecessary variables. del XBELEM, XBNODE, NumDof # Copy reference beam to current (deformed) variables. PosDefor = PosIni.copy(order='F') PsiDefor = PsiIni.copy(order='F') # Declare empty array for beam DoF rates. PosDotDef = np.zeros_like(PosDefor, ct.c_double, 'F') PsiDotDef = np.zeros_like(PsiDefor, ct.c_double, 'F') # Check the specified inputs from the PyAero have been properly applied. assert NumNodes_tot.value - 1 == VMOPTS.N.value, "Initialisation wrong" # Initialise section coordinates. Section = InitSection(VMOPTS, VMINPUT, AELOPTS.ElasticAxis) # Initialise origin and orientation of surface velocities in a-frame CGa = Psi2TransMat(VMUNST.PsiA_G) VelA_A = np.dot(CGa.T, VMUNST.VelA_G) OmegaA_A = np.dot(CGa.T, VMUNST.OmegaA_G) # Declare empty array for aerodynamic grid and velocities. Zeta = np.zeros((VMOPTS.M.value + 1, VMOPTS.N.value + 1, 3), ct.c_double, 'C') ZetaDot = np.zeros((VMOPTS.M.value + 1, VMOPTS.N.value + 1, 3), ct.c_double, 'C') # Initialise aerodynamic grid and velocities. CoincidentGrid(PosDefor, PsiDefor, Section, VelA_A, OmegaA_A, PosDotDef, PsiDotDef, XBINPUT, Zeta, ZetaDot, VMUNST.OriginA_G, VMUNST.PsiA_G, VMINPUT.ctrlSurf) # init wake ZetaStar, GammaStar = InitSteadyWake(VMOPTS, VMINPUT, Zeta) # init external velocities Uext = InitSteadyExternalVels(VMOPTS, VMINPUT) # Solver variables. Gamma = np.zeros((VMOPTS.M.value, VMOPTS.N.value), ct.c_double, 'C') Forces = np.zeros((VMOPTS.M.value + 1, VMOPTS.N.value + 1, 3), ct.c_double, 'C') # Solve UVLMLib.Cpp_Solver_VLM(Zeta, ZetaDot, Uext, ZetaStar, VMOPTS, Forces, Gamma, GammaStar) # Print tecplot file to check wake and grid etc Variables = ['X', 'Y', 'Z', 'Gamma'] # write header Filename = Settings.OutputDir + Settings.OutputFileRoot + 'AeroGrid.dat' FileObject = PostProcess.WriteAeroTecHeader(Filename, 'Default', Variables) # write surface zone data PostProcess.WriteAeroTecZone(FileObject, 'Surface', Zeta, -1, 0, 0.0, Variables, False, Gamma) # write wake data PostProcess.WriteAeroTecZone(FileObject, 'Wake', ZetaStar, -1, 0, 0.0, Variables, False, GammaStar) # close file PostProcess.CloseAeroTecFile(FileObject) if Settings.WriteUVLMdebug == True: debugFile = Settings.OutputDir + 'gamma_1degBeta.dat' np.savetxt(debugFile, Gamma.flatten('C')) # post process to get coefficients return PostProcess.GetCoeffs(VMOPTS, Forces, VMINPUT, VMUNST.VelA_G)
def Run_Cpp_Solver_UVLM(VMOPTS, VMINPUT, VMUNST, AELOPTS, vOmegaHist=None, eta0=None, numNodesElem=2, delEtaHist=None): """@brief UVLM solver with prescribed inputs. @param vOmegaHist None, or np.array history of velocities of the A-frame, expressed in A-frame. @param eta0 None, or tuple containing reference disps, rots, and gamma. @param delEtaHist None, or tuple of np.array histories of underlying beam disps, rotations, vels, and rotvels in A-frame.""" # Initialise DerivedTypes for PyBeam initialisation. XBOPTS = DerivedTypes.Xbopts() if numNodesElem == 2: beamElems = VMOPTS.N.value elif numNodesElem == 3: beamElems = int(VMOPTS.N.value / 2) else: raise ValueError('numNodesElem should be 2 or 3') XBINPUT = DerivedTypes.Xbinput(numNodesElem, beamElems, VMINPUT.b) # Create a dummy stiffness matrix to avoid errors. XBINPUT.BeamStiffness = np.eye(6, 6, 0, ct.c_double) # Use PyBeam to define reference beam (elastic axis). XBINPUT, XBOPTS, NumNodes_tot, XBELEM, PosIni, PsiIni,\ XBNODE, NumDof = BeamInit.Static(XBINPUT, XBOPTS) # Delete unnecessary variables. del XBELEM, XBNODE, NumDof # Copy reference beam to current (deformed) variables. if eta0 is None: PosDefor = PosIni.copy(order='F') PsiDefor = PsiIni.copy(order='F') else: PosDefor = eta0[0] #+delEtaHist[0][:,:,0] PsiDefor = eta0[1] #+delEtaHist[1][:,:,:,0] if delEtaHist is None: # Declare empty array for beam DoF rates. PosDotDef = np.zeros_like(PosDefor, ct.c_double, 'F') PsiDotDef = np.zeros_like(PsiDefor, ct.c_double, 'F') else: PosDotDef = delEtaHist[2][:, :, 0] PsiDotDef = delEtaHist[3][:, :, :, 0] # Check the specified inputs from the PyAero have been properly applied. assert NumNodes_tot.value - 1 == VMOPTS.N.value, "Initialisation wrong" # Initialise section coordinates. Section = InitSection(VMOPTS, VMINPUT, AELOPTS.ElasticAxis) # Initialise origin and orientation of surface velocities in a-frame CGa = Psi2TransMat(VMUNST.PsiA_G) if vOmegaHist is None: VelA_A = np.dot(CGa.T, VMUNST.VelA_G) OmegaA_A = np.dot(CGa.T, VMUNST.OmegaA_G) else: VelA_A = np.dot(CGa.T, vOmegaHist[0, 1:4]) OmegaA_A = np.dot(CGa.T, vOmegaHist[0, 4:7]) # Declare empty array for aerodynamic grid and velocities. Zeta = np.zeros((VMOPTS.M.value + 1, VMOPTS.N.value + 1, 3), ct.c_double, 'C') ZetaDot = np.zeros((VMOPTS.M.value + 1, VMOPTS.N.value + 1, 3), ct.c_double, 'C') # Initialise aerodynamic grid and velocities. CoincidentGrid(PosDefor, PsiDefor, Section, VelA_A, OmegaA_A, PosDotDef, PsiDotDef, XBINPUT, Zeta, ZetaDot, VMUNST.OriginA_G, VMUNST.PsiA_G, VMINPUT.ctrlSurf) # Initialise wake for unsteady solution. if vOmegaHist is None: velForWake = VMUNST.VelA_G else: velForWake = vOmegaHist[0, 1:4] ZetaStar, GammaStar = InitSteadyWake(VMOPTS, VMINPUT, Zeta, velForWake) # Initialise external velocities. Uext = InitSteadyExternalVels(VMOPTS, VMINPUT) # Declare empty solver variables. Forces = np.zeros_like(Zeta, ct.c_double, 'C') Gamma = np.zeros((VMOPTS.M.value, VMOPTS.N.value), ct.c_double, 'C') AIC = np.zeros( (VMOPTS.M.value * VMOPTS.N.value, VMOPTS.M.value * VMOPTS.N.value), ct.c_double, 'C') BIC = np.zeros( (VMOPTS.M.value * VMOPTS.N.value, VMOPTS.M.value * VMOPTS.N.value), ct.c_double, 'C') if type(eta0) is tuple: Gamma[:, :] = eta0[2] for j in range(VMOPTS.N.value): GammaStar[:, j] = Gamma[VMOPTS.M.value - 1, j] # Open tecplot file object." Variables = ['X', 'Y', 'Z', 'Gamma'] Filename = Settings.OutputDir + Settings.OutputFileRoot + 'AeroGrid.dat' FileObject = PostProcess.WriteAeroTecHeader(Filename, 'Default', Variables) # Initialise vector of time steps. Time = np.arange(0.0, VMUNST.FinalTime, VMOPTS.DelTime.value) # Create Array for storing time and coefficient data. CoeffHistory = np.zeros((len(Time), 4)) # Loop through time steps. for iTimeStep in range(len(Time)): # Set forces array to zero (+= operator used in C++ library). Forces[:, :, :] = 0.0 if iTimeStep > 0: # Update geometry. if vOmegaHist is None: VMUNST.OriginA_G[:] += VMUNST.VelA_G[:] * VMOPTS.DelTime.value # TODO: update OmegaA_A, PsiA_A in pitching problem. else: VMUNST.OriginA_G[:] += vOmegaHist[iTimeStep, 1:4] * VMOPTS.DelTime.value VelA_A = vOmegaHist[iTimeStep, 1:4] # TODO: update OmegaA_A, PsiA_G in pitching problem. if type(eta0) is tuple: PosDefor = eta0[0] PsiDefor = eta0[1] if type(delEtaHist) is tuple: PosDefor = PosDefor + delEtaHist[0][:, :, iTimeStep] PsiDefor = PsiDefor + delEtaHist[1][:, :, :, iTimeStep] PosDotDef = delEtaHist[ 2][:, :, iTimeStep] #TODO: PosDefor seems to be correct! PsiDotDef = delEtaHist[3][:, :, :, iTimeStep] # Update control surface defintion. if VMINPUT.ctrlSurf is not None: VMINPUT.ctrlSurf.update(Time[iTimeStep]) # Update aerodynamic surface. CoincidentGrid(PosDefor, PsiDefor, Section, VelA_A, OmegaA_A, PosDotDef, PsiDotDef, XBINPUT, Zeta, ZetaDot, VMUNST.OriginA_G, VMUNST.PsiA_G, VMINPUT.ctrlSurf) # Convect wake downstream. ZetaStar = np.roll(ZetaStar, 1, axis=0) GammaStar = np.roll(GammaStar, 1, axis=0) # Overwrite 1st row with with new trailing-edge position. ZetaStar[0, :] = Zeta[VMOPTS.M.value, :] # Overwrite Gamma with TE value from previous time step. GammaStar[0, :] = Gamma[VMOPTS.M.value - 1, :] # END if iTimeStep > 1 # Calculate forces on aerodynamic grid. if iTimeStep == 0: sav = VMOPTS.NewAIC VMOPTS.NewAIC = ct.c_bool(True) UVLMLib.Cpp_Solver_VLM(Zeta, ZetaDot, Uext, ZetaStar, VMOPTS, Forces, Gamma, GammaStar, AIC, BIC) if iTimeStep == 0: VMOPTS.NewAIC = sav del sav #print(PostProcess.GetCoeffs(VMOPTS, Forces, VMINPUT, VMUNST.VelA_G)) CoeffHistory[iTimeStep, 0] = Time[iTimeStep] CoeffHistory[iTimeStep, 1:] = PostProcess.GetCoeffs(VMOPTS, Forces, VMINPUT, VMUNST.VelA_G) # Write aerodynamic surface data as tecplot zone data. PostProcess.WriteAeroTecZone(FileObject, 'Surface', Zeta,\ iTimeStep, len(Time),\ Time[iTimeStep], Variables, False, Gamma) # Write wake data as tecplot zone data. PostProcess.WriteAeroTecZone(FileObject, 'Wake', ZetaStar,\ iTimeStep, len(Time),\ Time[iTimeStep], \ Variables, False, GammaStar) # Rollup due to external velocities. ZetaStar[:, :] += VMINPUT.U_infty * VMOPTS.DelTime.value # END for iTimeStep # Close tecplot file object. PostProcess.CloseAeroTecFile(FileObject) # write geometry and circ dist. to file for matlab if iTimeStep == len(Time) - 1 and False: savemat('/home/rjs10/Desktop/uvlmOut.mat', { 'zeta': Zeta.flatten('C'), 'zetaW': ZetaStar.flatten('C'), 'gamma': Gamma.flatten('C'), 'gammaW': GammaStar.flatten('C') }, False, oned_as='column') return CoeffHistory
def Run_Cpp_Solver_UVLM(VMOPTS, VMINPUT, VMUNST, AELOPTS): """@brief UVLM solver with prescribed inputs.""" # Initialise DerivedTypes for PyBeam initialisation. XBOPTS = DerivedTypes.Xbopts() XBINPUT = DerivedTypes.Xbinput(2, VMOPTS.N.value, VMINPUT.b) # Create a dummy stiffness matrix to avoid errors. XBINPUT.BeamStiffness = np.eye(6, 6, 0, ct.c_double) # Use PyBeam to define reference beam (elastic axis). XBINPUT, XBOPTS, NumNodes_tot, XBELEM, PosIni, PsiIni,\ XBNODE, NumDof = BeamInit.Static(XBINPUT, XBOPTS) # Delete unnecessary variables. del XBELEM, XBNODE, NumDof # Copy reference beam to current (deformed) variables. PosDefor = PosIni.copy(order='F') PsiDefor = PsiIni.copy(order='F') # Declare empty array for beam DoF rates. PosDotDef = np.zeros_like(PosDefor, ct.c_double, 'F') PsiDotDef = np.zeros_like(PsiDefor, ct.c_double, 'F') # Check the specified inputs from the PyAero have been properly applied. assert NumNodes_tot.value - 1 == VMOPTS.N.value, "Initialisation wrong" # Initialise section coordinates. Section = InitSection(VMOPTS, VMINPUT, AELOPTS.ElasticAxis) # Initialise origin and orientation of surface velocities in a-frame CGa = Psi2TransMat(VMUNST.PsiA_G) VelA_A = np.dot(CGa.T, VMUNST.VelA_G) OmegaA_A = np.dot(CGa.T, VMUNST.OmegaA_G) # Declare empty array for aerodynamic grid and velocities. Zeta = np.zeros((VMOPTS.M.value + 1, VMOPTS.N.value + 1, 3), ct.c_double, 'C') ZetaDot = np.zeros((VMOPTS.M.value + 1, VMOPTS.N.value + 1, 3), ct.c_double, 'C') # Initialise aerodynamic grid and velocities. CoincidentGrid(PosDefor, PsiDefor, Section, VelA_A, OmegaA_A, PosDotDef, PsiDotDef, XBINPUT, Zeta, ZetaDot, VMUNST.OriginA_G, VMUNST.PsiA_G, VMINPUT.ctrlSurf) # Initialise wake for unsteady solution. ZetaStar, GammaStar = InitSteadyWake(VMOPTS, VMINPUT, Zeta, VMUNST.VelA_G) # Initialise external velocities. Uext = InitSteadyExternalVels(VMOPTS, VMINPUT) # Declare empty solver variables. Forces = np.zeros_like(Zeta, ct.c_double, 'C') Gamma = np.zeros((VMOPTS.M.value, VMOPTS.N.value), ct.c_double, 'C') AIC = np.zeros( (VMOPTS.M.value * VMOPTS.N.value, VMOPTS.M.value * VMOPTS.N.value), ct.c_double, 'C') BIC = np.zeros( (VMOPTS.M.value * VMOPTS.N.value, VMOPTS.M.value * VMOPTS.N.value), ct.c_double, 'C') # Open tecplot file object." Variables = ['X', 'Y', 'Z', 'Gamma'] Filename = Settings.OutputDir + Settings.OutputFileRoot + 'AeroGrid.dat' FileObject = PostProcess.WriteAeroTecHeader(Filename, 'Default', Variables) # Initialise vector of time steps. Time = np.arange(0.0, VMUNST.FinalTime + VMUNST.DelTime, VMUNST.DelTime) # Create Array for storing time and coefficient data. CoeffHistory = np.zeros((len(Time), 4)) # Loop through time steps. for iTimeStep in range(len(Time)): # Set forces array to zero (+= operator used in C++ library). Forces[:, :, :] = 0.0 if iTimeStep > 0: # Update geometry. VMUNST.OriginA_G[:] += VMUNST.VelA_G[:] * VMUNST.DelTime # TODO: update OmegaA_A in pitching problem. # Update control surface defintion. if VMINPUT.ctrlSurf != None: VMINPUT.ctrlSurf.update(Time[iTimeStep]) # Update aerodynamic surface. CoincidentGrid(PosDefor, PsiDefor, Section, VelA_A, OmegaA_A, PosDotDef, PsiDotDef, XBINPUT, Zeta, ZetaDot, VMUNST.OriginA_G, VMUNST.PsiA_G, VMINPUT.ctrlSurf) # Convect wake downstream. ZetaStar = np.roll(ZetaStar, 1, axis=0) GammaStar = np.roll(GammaStar, 1, axis=0) # Overwrite 1st row with with new trailing-edge position. ZetaStar[0, :] = Zeta[VMOPTS.M.value, :] # Overwrite Gamma with TE value from previous time step. GammaStar[0, :] = Gamma[VMOPTS.M.value - 1, :] # set NewAIC to false. if VMINPUT.ctrlSurf == False: VMOPTS.NewAIC = ct.c_bool(False) # END if iTimeStep > 1 # Calculate forces on aerodynamic grid. UVLMLib.Cpp_Solver_VLM(Zeta, ZetaDot, Uext, ZetaStar, VMOPTS, Forces, Gamma, GammaStar, AIC, BIC) #print(PostProcess.GetCoeffs(VMOPTS, Forces, VMINPUT, VMUNST.VelA_G)) CoeffHistory[iTimeStep, 0] = Time[iTimeStep] CoeffHistory[iTimeStep, 1:] = PostProcess.GetCoeffs(VMOPTS, Forces, VMINPUT, VMUNST.VelA_G) # Write aerodynamic surface data as tecplot zone data. PostProcess.WriteAeroTecZone(FileObject, 'Surface', Zeta,\ iTimeStep, len(Time),\ Time[iTimeStep], Variables, False, Gamma) # Write wake data as tecplot zone data. PostProcess.WriteAeroTecZone(FileObject, 'Wake', ZetaStar,\ iTimeStep, len(Time),\ Time[iTimeStep], \ Variables, False, GammaStar) # Rollup due to external velocities. ZetaStar[:, :] += VMINPUT.U_infty * VMOPTS.DelTime.value # END for iTimeStep # Close tecplot file object. PostProcess.CloseAeroTecFile(FileObject) return CoeffHistory