def Solve_Py(XBINPUT,XBOPTS,VMOPTS,VMINPUT,AELAOPTS,**kwords): """@brief Nonlinear dynamic solver using Python to solve aeroelastic equation. @details Assembly of structural matrices is carried out with Fortran subroutines. Aerodynamics solved using PyAero\.UVLM. @param XBINPUT Beam inputs (for initialization in Python). @param XBOPTS Beam solver options (for Fortran). @param VMOPTS UVLM solver options (for C/C++). @param VMINPUT UVLM solver inputs (for initialization in Python). @param VMUNST Unsteady input information for aero solver. @param AELAOPTS Options relevant to coupled aeroelastic simulations. @param writeDict OrderedDict of 'name':tuple of outputs to write. """ # Check correct solution code. assert XBOPTS.Solution.value == 912, ('NonlinearFlightDynamic requested' + ' with wrong solution code') # Initialise static beam data. XBINPUT, XBOPTS, NumNodes_tot, XBELEM, PosIni, PsiIni, XBNODE, NumDof \ = BeamInit.Static(XBINPUT,XBOPTS) # Calculate initial displacements. if AELAOPTS.ImpStart == False: XBOPTS.Solution.value = 112 # Modify options. VMOPTS.Steady = ct.c_bool(True) Rollup = VMOPTS.Rollup.value VMOPTS.Rollup.value = False # Solve Static Aeroelastic. PosDefor, PsiDefor, Zeta, ZetaStar, Gamma, GammaStar, Force = \ Static.Solve_Py(XBINPUT, XBOPTS, VMOPTS, VMINPUT, AELAOPTS) XBOPTS.Solution.value = 912 # Reset options. VMOPTS.Steady = ct.c_bool(False) VMOPTS.Rollup.value = Rollup elif AELAOPTS.ImpStart == True: PosDefor = PosIni.copy(order='F') PsiDefor = PsiIni.copy(order='F') Force = np.zeros((XBINPUT.NumNodesTot,6),ct.c_double,'F') # Write deformed configuration to file. TODO: tidy this away inside function. ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL912_def.dat' if XBOPTS.PrintInfo==True: sys.stdout.write('Writing file %s ... ' %(ofile)) fp = open(ofile,'w') fp.write('TITLE="Non-linear static solution: deformed geometry"\n') fp.write('VARIABLES="iElem" "iNode" "Px" "Py" "Pz" "Rx" "Ry" "Rz"\n') fp.close() if XBOPTS.PrintInfo==True: sys.stdout.write('done\n') WriteMode = 'a' # Write BeamIO.OutputElems(XBINPUT.NumElems, NumNodes_tot.value, XBELEM, PosDefor, PsiDefor, ofile, WriteMode) # Initialise structural variables for dynamic analysis. Time, NumSteps, ForceTime, Vrel, VrelDot,\ PosDotDef, PsiDotDef,\ OutGrids, PosPsiTime, VelocTime, DynOut\ = BeamInit.Dynamic(XBINPUT,XBOPTS) # Delete unused variables. del OutGrids, VelocTime if XBOPTS.PrintInfo.value==True: sys.stdout.write('Solve nonlinear dynamic case in Python ... \n') #Initialise structural system tensors MssFull = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F') CssFull = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F') KssFull = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F') FstrucFull = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F') ms = ct.c_int() cs = ct.c_int() ks = ct.c_int() fs = ct.c_int() Msr = np.zeros((NumDof.value,6), ct.c_double, 'F') Csr = np.zeros((NumDof.value,6), ct.c_double, 'F') X = np.zeros(NumDof.value, ct.c_double, 'F') dXdt = np.zeros(NumDof.value, ct.c_double, 'F') Force_Dof = np.zeros(NumDof.value, ct.c_double, 'F') Qstruc = np.zeros(NumDof.value, ct.c_double, 'F') #Initialise rigid-body system tensors MrsFull = np.zeros((6,NumDof.value), ct.c_double, 'F') CrsFull = np.zeros((6,NumDof.value), ct.c_double, 'F') KrsFull = np.zeros((6,NumDof.value), ct.c_double, 'F') FrigidFull = np.zeros((6,NumDof.value+6), ct.c_double, 'F') mr = ct.c_int() cr = ct.c_int() kr = ct.c_int() fr = ct.c_int() Mrr = np.zeros((6,6), ct.c_double, 'F') Crr = np.zeros((6,6), ct.c_double, 'F') Qrigid = np.zeros(6, ct.c_double, 'F') #Initialise full system tensors Q = np.zeros(NumDof.value+6+4, ct.c_double, 'F') DQ = np.zeros(NumDof.value+6+4, ct.c_double, 'F') dQdt = np.zeros(NumDof.value+6+4, ct.c_double, 'F') dQddt = np.zeros(NumDof.value+6+4, ct.c_double, 'F') Force_All = np.zeros(NumDof.value+6, ct.c_double, 'F') Msys = np.zeros((NumDof.value+6+4,NumDof.value+6+4), ct.c_double, 'F') Csys = np.zeros((NumDof.value+6+4,NumDof.value+6+4), ct.c_double, 'F') Ksys = np.zeros((NumDof.value+6+4,NumDof.value+6+4), ct.c_double, 'F') Asys = np.zeros((NumDof.value+6+4,NumDof.value+6+4), ct.c_double, 'F') Qsys = np.zeros(NumDof.value+6+4, ct.c_double, 'F') #Initialise rotation operators. TODO: include initial AOA here currVrel=Vrel[0,:].copy('F') AOA = np.arctan(currVrel[2]/-currVrel[1]) Quat = xbl.Euler2Quat(AOA,0,0) Cao = xbl.Rot(Quat) ACoa = np.zeros((6,6), ct.c_double, 'F') ACoa[:3,:3] = np.transpose(Cao) ACoa[3:,3:] = np.transpose(Cao) Cqr = np.zeros((4,6), ct.c_double, 'F') Cqq = np.zeros((4,4), ct.c_double, 'F') Unit4 = np.zeros((4,4), ct.c_double, 'F') for i in range(4): Unit4[i,i] = 1.0 # Extract initial displacements and velocities. BeamLib.Cbeam_Solv_Disp2State(NumNodes_tot, NumDof, XBINPUT, XBNODE, PosDefor, PsiDefor, PosDotDef, PsiDotDef, X, dXdt) # Approximate initial accelerations. PosDotDotDef = np.zeros((NumNodes_tot.value,3),ct.c_double,'F') PsiDotDotDef = np.zeros((XBINPUT.NumElems,Settings.MaxElNod,3), ct.c_double, 'F') #Populate state vector Q[:NumDof.value]=X.copy('F') dQdt[:NumDof.value]=dXdt.copy('F') dQdt[NumDof.value:NumDof.value+6] = Vrel[0,:].copy('F') dQdt[NumDof.value+6:]= Quat.copy('F') #Force at the first time-step Force += (XBINPUT.ForceDyn*ForceTime[0]).copy('F') #Assemble matrices and loads for structural dynamic analysis currVrel=Vrel[0,:].copy('F') tmpQuat=Quat.copy('F') BeamLib.Cbeam3_Asbly_Dynamic(XBINPUT, NumNodes_tot, XBELEM, XBNODE,\ PosIni, PsiIni, PosDefor, PsiDefor,\ PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef,\ Force, currVrel, 0*currVrel,\ NumDof, Settings.DimMat,\ ms, MssFull, Msr,\ cs, CssFull, Csr,\ ks, KssFull, fs, FstrucFull,\ Qstruc, XBOPTS, Cao) BeamLib.f_fem_m2v(ct.byref(NumNodes_tot),\ ct.byref(ct.c_int(6)),\ Force.ctypes.data_as(ct.POINTER(ct.c_double)),\ ct.byref(NumDof),\ Force_Dof.ctypes.data_as(ct.POINTER(ct.c_double)),\ XBNODE.Vdof.ctypes.data_as(ct.POINTER(ct.c_int)) ) Qstruc -= np.dot(FstrucFull, Force_Dof) #Assemble matrices for rigid-body dynamic analysis BeamLib.Xbeam_Asbly_Dynamic(XBINPUT, NumNodes_tot, XBELEM, XBNODE,\ PosIni, PsiIni, PosDefor, PsiDefor,\ PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef,\ currVrel, 0*currVrel, tmpQuat,\ NumDof, Settings.DimMat,\ mr, MrsFull, Mrr,\ cr, CrsFull, Crr, Cqr, Cqq,\ kr, KrsFull, fr, FrigidFull,\ Qrigid, XBOPTS, Cao) BeamLib.f_fem_m2v_nofilter(ct.byref(NumNodes_tot),\ ct.byref(ct.c_int(6)),\ Force.ctypes.data_as(ct.POINTER(ct.c_double)),\ ct.byref(ct.c_int(NumDof.value+6)),\ Force_All.ctypes.data_as(ct.POINTER(ct.c_double)) ) Qrigid -= np.dot(FrigidFull, Force_All) # #Separate assembly of follower and dead loads # tmpForceTime=ForceTime[0].copy('F') # tmpQforces,Dummy,tmpQrigid = xbl.LoadAssembly(XBINPUT, XBELEM, XBNODE, XBOPTS, NumDof, \ # PosIni, PsiIni, PosDefor, PsiDefor, \ # (XBINPUT.ForceStatic_foll + XBINPUT.ForceDyn_foll*tmpForceTime), \ # (XBINPUT.ForceStatic_dead + XBINPUT.ForceDyn_dead*tmpForceTime), \ # Cao,1) # # Qstruc -= tmpQforces # Qrigid -= tmpQrigid #Assemble system matrices Msys[:NumDof.value,:NumDof.value] = MssFull.copy('F') Msys[:NumDof.value,NumDof.value:NumDof.value+6] = Msr.copy('F') Msys[NumDof.value:NumDof.value+6,:NumDof.value] = MrsFull.copy('F') Msys[NumDof.value:NumDof.value+6,NumDof.value:NumDof.value+6] = Mrr.copy('F') Msys[NumDof.value+6:,NumDof.value+6:] = Unit4.copy('F') Qsys[:NumDof.value] = Qstruc Qsys[NumDof.value:NumDof.value+6] = Qrigid Qsys[NumDof.value+6:] = np.dot(Cqq,dQdt[NumDof.value+6:]) # Initial Accel. dQddt[:] = np.dot(np.linalg.inv(Msys), -Qsys) #Record position of all grid points in global FoR at initial time step DynOut[0:NumNodes_tot.value,:] = PosDefor #Position/rotation of the selected node in initial deformed configuration PosPsiTime[0,:3] = PosDefor[-1,:] PosPsiTime[0,3:] = PsiDefor[-1,XBELEM.NumNodes[-1]-1,:] #Get gamma and beta for Newmark scheme gamma = 0.5 + XBOPTS.NewmarkDamp.value beta = 0.25*(gamma + 0.5)**2 # Initialise Aero Section = InitSection(VMOPTS,VMINPUT,AELAOPTS.ElasticAxis) # Declare memory for Aero variables. ZetaDot = np.zeros((Section.shape[0],PosDefor.shape[0],3),ct.c_double,'C') K = VMOPTS.M.value*VMOPTS.N.value AIC = np.zeros((K,K),ct.c_double,'C') BIC = np.zeros((K,K),ct.c_double,'C') AeroForces = np.zeros((VMOPTS.M.value+1,VMOPTS.N.value+1,3),ct.c_double,'C') # Initialise A-frame location and orientation to be zero. OriginA_G = np.zeros(3,ct.c_double,'C') PsiA_G = xbl.quat2psi(Quat) # CRV at iStep # Init external velocities. Ufree = InitSteadyExternalVels(VMOPTS,VMINPUT) if AELAOPTS.ImpStart == True: Zeta = np.zeros((Section.shape[0],PosDefor.shape[0],3),ct.c_double,'C') Gamma = np.zeros((VMOPTS.M.value,VMOPTS.N.value),ct.c_double,'C') # Generate surface, wake and gamma matrices. CoincidentGrid(PosDefor, PsiDefor, Section, currVrel[:3], currVrel[3:], PosDotDef, PsiDotDef, XBINPUT, Zeta, ZetaDot, OriginA_G, PsiA_G, VMINPUT.ctrlSurf) # init wake grid and gamma matrix. ZetaStar, GammaStar = InitSteadyWake(VMOPTS,VMINPUT,Zeta,currVrel[:3]) # Define tecplot stuff if Settings.PlotTec==True: FileName = Settings.OutputDir + Settings.OutputFileRoot + 'AeroGrid.dat' Variables = ['X', 'Y', 'Z','Gamma'] FileObject = PostProcess.WriteAeroTecHeader(FileName, 'Default', Variables) # Plot results of static analysis PostProcess.WriteUVLMtoTec(FileObject, Zeta, ZetaStar, Gamma, GammaStar, TimeStep = 0, NumTimeSteps = XBOPTS.NumLoadSteps.value, Time = 0.0, Text = True) # Open output file for writing if 'writeDict' in kwords and Settings.WriteOut == True: writeDict = kwords['writeDict'] ofile = Settings.OutputDir + \ Settings.OutputFileRoot + \ '_SOL912_out.dat' fp = open(ofile,'w') fp.write("{:<14}".format("Time")) for output in writeDict.keys(): fp.write("{:<14}".format(output)) fp.write("\n") fp.flush() # Write initial outputs to file. if 'writeDict' in kwords and Settings.WriteOut == True: locForces = None # Stops recalculation of forces fp.write("{:<14,e}".format(Time[0])) for myStr in writeDict.keys(): if re.search(r'^R_.',myStr): if re.search(r'^R_._.', myStr): index = int(myStr[4]) elif re.search(r'root', myStr): index = 0 elif re.search(r'tip', myStr): index = -1 else: raise IOError("Node index not recognised.") if myStr[2] == 'x': component = 0 elif myStr[2] == 'y': component = 1 elif myStr[2] == 'z': component = 2 else: raise IOError("Displacement component not recognised.") fp.write("{:<14,e}".format(PosDefor[index,component])) elif re.search(r'^M_.',myStr): if re.search(r'^M_._.', myStr): index = int(myStr[4]) elif re.search(r'root', myStr): index = 0 elif re.search(r'tip', myStr): index = -1 else: raise IOError("Node index not recognised.") if myStr[2] == 'x': component = 0 elif myStr[2] == 'y': component = 1 elif myStr[2] == 'z': component = 2 else: raise IOError("Moment component not recognised.") if locForces == None: locForces = BeamIO.localElasticForces(PosDefor, PsiDefor, PosIni, PsiIni, XBELEM, [index]) fp.write("{:<14,e}".format(locForces[0,3+component])) else: raise IOError("writeDict key not recognised.") # END for myStr fp.write("\n") fp.flush() # END if write # Time loop. for iStep in range(NumSteps.value): if XBOPTS.PrintInfo.value==True: sys.stdout.write('Time: %-10.4e\n' %(Time[iStep+1])) sys.stdout.write(' SubIter DeltaF DeltaX ResLog10\n') #calculate dt dt = Time[iStep+1] - Time[iStep] # Set dt for aero force calcs. VMOPTS.DelTime = ct.c_double(dt) #Predictor step Q += dt*dQdt + (0.5-beta)*dQddt*np.power(dt,2.0) dQdt += (1.0-gamma)*dQddt*dt dQddt[:] = 0.0 # Quaternion update for orientation. Quat = dQdt[NumDof.value+6:].copy('F') Quat = Quat/np.linalg.norm(Quat) Cao = xbl.Rot(Quat) #nodal diplacements and velocities from state vector X=Q[:NumDof.value].copy('F') dXdt=dQdt[:NumDof.value].copy('F'); BeamLib.Cbeam3_Solv_State2Disp(XBINPUT,NumNodes_tot,XBELEM,XBNODE, PosIni,PsiIni,NumDof,X,dXdt, PosDefor,PsiDefor,PosDotDef,PsiDotDef) # Force at current time-step. TODO: Check communication flow. if iStep > 0 and AELAOPTS.Tight == False: # zero aero forces. AeroForces[:,:,:] = 0.0 # Update CRV. PsiA_G = xbl.quat2psi(Quat) # CRV at iStep # Update origin. currVrel=Vrel[iStep-1,:].copy('F') OriginA_G[:] = OriginA_G[:] + currVrel[:3]*dt # Update control surface deflection. if VMINPUT.ctrlSurf != None: VMINPUT.ctrlSurf.update(Time[iStep]) # Generate surface grid. currVrel=Vrel[iStep,:].copy('F') CoincidentGrid(PosDefor, PsiDefor, Section, currVrel[:3], currVrel[3:], PosDotDef, PsiDotDef, XBINPUT, Zeta, ZetaDot, OriginA_G, PsiA_G, VMINPUT.ctrlSurf) # Update wake geom #'roll' data. ZetaStar = np.roll(ZetaStar,1,axis = 0) GammaStar = np.roll(GammaStar,1,axis = 0) #overwrite grid points with TE. ZetaStar[0,:] = Zeta[VMOPTS.M.value,:] # overwrite Gamma with TE value from previous timestep. GammaStar[0,:] = Gamma[VMOPTS.M.value-1,:] # Apply gust velocity. if VMINPUT.gust != None: Utot = Ufree + VMINPUT.gust.Vels(Zeta) else: Utot = Ufree # Solve for AeroForces UVLMLib.Cpp_Solver_VLM(Zeta, ZetaDot, Utot, ZetaStar, VMOPTS, AeroForces, Gamma, GammaStar, AIC, BIC) # Apply density scaling AeroForces[:,:,:] = AELAOPTS.AirDensity*AeroForces[:,:,:] if Settings.PlotTec==True: PostProcess.WriteUVLMtoTec(FileObject, Zeta, ZetaStar, Gamma, GammaStar, TimeStep = iStep, NumTimeSteps = XBOPTS.NumLoadSteps.value, Time = Time[iStep], Text = True) # map AeroForces to beam. CoincidentGridForce(XBINPUT, PsiDefor, Section, AeroForces, Force) # Add gravity loads. AddGravityLoads(Force, XBINPUT, XBELEM, AELAOPTS, PsiDefor, VMINPUT.c) # Add thrust and other point loads Force += (XBINPUT.ForceStatic + XBINPUT.ForceDyn*ForceTime[iStep+1]).copy('F') #END if iStep > 0 #Reset convergence parameters Iter = 0 ResLog10 = 1.0 #Newton-Raphson loop while ( (ResLog10 > XBOPTS.MinDelta.value) \ & (Iter < XBOPTS.MaxIterations.value) ): #set tensors to zero MssFull[:,:] = 0.0; CssFull[:,:] = 0.0 KssFull[:,:] = 0.0; FstrucFull[:,:] = 0.0 Msr[:,:] = 0.0; Csr[:,:] = 0.0 Qstruc[:] = 0.0 MrsFull[:,:] = 0.0; CrsFull[:,:] = 0.0 KrsFull[:,:] = 0.0; FrigidFull[:,:] = 0.0 Mrr[:,:] = 0.0; Crr[:,:] = 0.0 Qrigid[:] = 0.0 Msys[:,:] = 0.0; Csys[:,:] = 0.0 Ksys[:,:] = 0.0; Asys[:,:] = 0.0; Qsys[:] = 0.0 # Update counter. Iter += 1 if XBOPTS.PrintInfo.value==True: sys.stdout.write(' %-7d ' %(Iter)) #nodal diplacements and velocities from state vector X=Q[:NumDof.value].copy('F') dXdt=dQdt[:NumDof.value].copy('F'); BeamLib.Cbeam3_Solv_State2Disp(XBINPUT, NumNodes_tot, XBELEM, XBNODE, PosIni, PsiIni, NumDof, X, dXdt, PosDefor, PsiDefor, PosDotDef, PsiDotDef) #rigid-body velocities and orientation from state vector Vrel[iStep+1,:] = dQdt[NumDof.value:NumDof.value+6].copy('F') VrelDot[iStep+1,:] = dQddt[NumDof.value:NumDof.value+6].copy('F') Quat = dQdt[NumDof.value+6:].copy('F') Quat = Quat/np.linalg.norm(Quat) Cao = xbl.Rot(Quat) #Update matrices and loads for structural dynamic analysis tmpVrel=Vrel[iStep+1,:].copy('F') tmpQuat=Quat.copy('F') BeamLib.Cbeam3_Asbly_Dynamic(XBINPUT, NumNodes_tot, XBELEM, XBNODE,\ PosIni, PsiIni, PosDefor, PsiDefor,\ PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef,\ Force, tmpVrel, 0*tmpVrel,\ NumDof, Settings.DimMat,\ ms, MssFull, Msr,\ cs, CssFull, Csr,\ ks, KssFull, fs, FstrucFull,\ Qstruc, XBOPTS, Cao) BeamLib.f_fem_m2v(ct.byref(NumNodes_tot),\ ct.byref(ct.c_int(6)),\ Force.ctypes.data_as(ct.POINTER(ct.c_double)),\ ct.byref(NumDof),\ Force_Dof.ctypes.data_as(ct.POINTER(ct.c_double)),\ XBNODE.Vdof.ctypes.data_as(ct.POINTER(ct.c_int)) ) #Update matrices for rigid-body dynamic analysis BeamLib.Xbeam_Asbly_Dynamic(XBINPUT, NumNodes_tot, XBELEM, XBNODE,\ PosIni, PsiIni, PosDefor, PsiDefor,\ PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef,\ tmpVrel, 0*tmpVrel, tmpQuat,\ NumDof, Settings.DimMat,\ mr, MrsFull, Mrr,\ cr, CrsFull, Crr, Cqr, Cqq,\ kr, KrsFull, fs, FrigidFull,\ Qrigid, XBOPTS, Cao) BeamLib.f_fem_m2v_nofilter(ct.byref(NumNodes_tot),\ ct.byref(ct.c_int(6)),\ Force.ctypes.data_as(ct.POINTER(ct.c_double)),\ ct.byref(ct.c_int(NumDof.value+6)),\ Force_All.ctypes.data_as(ct.POINTER(ct.c_double)) ) #Residual at first iteration if(Iter == 1): Res0_Qglobal = max(max(abs(Qsys)),1) Res0_DeltaX = max(max(abs(DQ)),1) #Assemble discrete system matrices with linearised quaternion equations Msys[:NumDof.value,:NumDof.value] = MssFull.copy('F') Msys[:NumDof.value,NumDof.value:NumDof.value+6] = Msr.copy('F') Msys[NumDof.value:NumDof.value+6,:NumDof.value] = MrsFull.copy('F') Msys[NumDof.value:NumDof.value+6,NumDof.value:NumDof.value+6] = Mrr.copy('F') Msys[NumDof.value+6:,NumDof.value+6:] = Unit4.copy('F') Csys[:NumDof.value,:NumDof.value] = CssFull.copy('F') Csys[:NumDof.value,NumDof.value:NumDof.value+6] = Csr.copy('F') Csys[NumDof.value:NumDof.value+6,:NumDof.value] = CrsFull.copy('F') Csys[NumDof.value:NumDof.value+6,NumDof.value:NumDof.value+6] = Crr.copy('F') Csys[NumDof.value+6:,NumDof.value:NumDof.value+6] = Cqr.copy('F') Csys[NumDof.value+6:,NumDof.value+6:] = Cqq.copy('F') Ksys[:NumDof.value,:NumDof.value] = KssFull.copy('F') Ksys[NumDof.value:NumDof.value+6,:NumDof.value] = KrsFull.copy('F') # #Separate assembly of follower and dead loads # tmpForceTime=ForceTime[iStep+1].copy('F') # tmpQforces,Dummy,tmpQrigid = xbl.LoadAssembly(XBINPUT, XBELEM, XBNODE, XBOPTS, NumDof, \ # PosIni, PsiIni, PosDefor, PsiDefor, \ # (XBINPUT.ForceStatic_foll + XBINPUT.ForceDyn_foll*tmpForceTime), \ # (XBINPUT.ForceStatic_dead + XBINPUT.ForceDyn_dead*tmpForceTime), \ # Cao,1) # # Qstruc -= tmpQforces # Qrigid -= tmpQrigid #Compute residual to solve update vector Qstruc += -np.dot(FstrucFull, Force_Dof) Qrigid += -np.dot(FrigidFull, Force_All) Qsys[:NumDof.value] = Qstruc Qsys[NumDof.value:NumDof.value+6] = Qrigid Qsys[NumDof.value+6:] = np.dot(Cqq,dQdt[NumDof.value+6:]) Qsys += np.dot(Msys,dQddt) #Calculate system matrix for update calculation Asys = Ksys + \ Csys*gamma/(beta*dt) + \ Msys/(beta*dt**2) #Compute correction DQ[:] = np.dot(np.linalg.inv(Asys), -Qsys) Q += DQ dQdt += DQ*gamma/(beta*dt) dQddt += DQ/(beta*dt**2) #Update convergence criteria if XBOPTS.PrintInfo.value==True: sys.stdout.write('%-10.4e ' %(max(abs(Qsys)))) Res_Qglobal = max(abs(Qsys)) Res_DeltaX = max(abs(DQ)) ResLog10 = max(Res_Qglobal/Res0_Qglobal,Res_DeltaX/Res0_DeltaX) if XBOPTS.PrintInfo.value==True: sys.stdout.write('%-10.4e %8.4f\n' %(max(abs(DQ)),ResLog10)) # END Netwon-Raphson. #update to converged nodal displacements and velocities X=Q[:NumDof.value].copy('F') dXdt=dQdt[:NumDof.value].copy('F'); BeamLib.Cbeam3_Solv_State2Disp(XBINPUT, NumNodes_tot, XBELEM, XBNODE, PosIni, PsiIni, NumDof, X, dXdt,\ PosDefor, PsiDefor, PosDotDef, PsiDotDef) PosPsiTime[iStep+1,:3] = PosDefor[-1,:] PosPsiTime[iStep+1,3:] = PsiDefor[-1,XBELEM.NumNodes[-1]-1,:] #Position of all grid points in global FoR i1 = (iStep+1)*NumNodes_tot.value i2 = (iStep+2)*NumNodes_tot.value DynOut[i1:i2,:] = PosDefor #Export rigid-body velocities/accelerations if XBOPTS.OutInaframe.value==True: Vrel[iStep,:] = dQdt[NumDof.value:NumDof.value+6].copy('F') VrelDot[iStep,:] = dQddt[NumDof.value:NumDof.value+6].copy('F') else: Quat = dQdt[NumDof.value+6:].copy('F') Quat = Quat/np.linalg.norm(Quat) Cao = xbl.Rot(Quat) ACoa[:3,:3] = np.transpose(Cao) ACoa[3:,3:] = np.transpose(Cao) Vrel[iStep,:] = np.dot(ACoa,dQdt[NumDof.value:NumDof.value+6].copy('F')) VrelDot[iStep,:] = np.dot(ACoa,dQddt[NumDof.value:NumDof.value+6].copy('F')) # Write selected outputs # tidy this away using function. if 'writeDict' in kwords and Settings.WriteOut == True: locForces = None # Stops recalculation of forces fp.write("{:<14,e}".format(Time[iStep+1])) for myStr in writeDict.keys(): if re.search(r'^R_.',myStr): if re.search(r'^R_._.', myStr): index = int(myStr[4]) elif re.search(r'root', myStr): index = 0 elif re.search(r'tip', myStr): index = -1 else: raise IOError("Node index not recognised.") if myStr[2] == 'x': component = 0 elif myStr[2] == 'y': component = 1 elif myStr[2] == 'z': component = 2 else: raise IOError("Displacement component not recognised.") fp.write("{:<14,e}".format(PosDefor[index,component])) elif re.search(r'^M_.',myStr): if re.search(r'^M_._.', myStr): index = int(myStr[4]) elif re.search(r'root', myStr): index = 0 elif re.search(r'tip', myStr): index = -1 else: raise IOError("Node index not recognised.") if myStr[2] == 'x': component = 0 elif myStr[2] == 'y': component = 1 elif myStr[2] == 'z': component = 2 else: raise IOError("Moment component not recognised.") if locForces == None: locForces = BeamIO.localElasticForces(PosDefor, PsiDefor, PosIni, PsiIni, XBELEM, [index]) fp.write("{:<14,e}".format(locForces[0,3+component])) else: raise IOError("writeDict key not recognised.") # END for myStr fp.write("\n") fp.flush() # 'Rollup' due to external velocities. TODO: Must add gusts here! ZetaStar[:,:] = ZetaStar[:,:] + VMINPUT.U_infty*dt # END Time loop # Write _dyn file. ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL912_dyn.dat' fp = open(ofile,'w') BeamIO.Write_dyn_File(fp, Time, PosPsiTime) fp.close() #Write _shape file ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL912_shape.dat' fp = open(ofile,'w') BeamIO.Write_shape_File(fp, len(Time), NumNodes_tot.value, Time, DynOut) fp.close() #Write rigid-body velocities ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL912_rigid.dat' fp = open(ofile,'w') BeamIO.Write_rigid_File(fp, Time, Vrel, VrelDot) fp.close() # Close output file if it exists. if 'writeDict' in kwords and Settings.WriteOut == True: fp.close() # Close Tecplot ascii FileObject. if Settings.PlotTec==True: PostProcess.CloseAeroTecFile(FileObject) if XBOPTS.PrintInfo.value==True: sys.stdout.write(' ... done\n') # For interactive analysis at end of simulation set breakpoint. pass
def Solve_Py(XBINPUT,XBOPTS, moduleName = None): """Nonlinear dynamic structural solver in Python. Assembly of matrices is carried out with Fortran subroutines.""" "Check correct solution code" assert XBOPTS.Solution.value == 312, ('NonlinearDynamic requested' +\ ' with wrong solution code') "Initialise beam" XBINPUT, XBOPTS, NumNodes_tot, XBELEM, PosIni, PsiIni, XBNODE, NumDof \ = BeamInit.Static(XBINPUT,XBOPTS, moduleName) # Solve static solution XBOPTS.Solution.value = 112 PosDefor, PsiDefor = Solve_Py_Static(XBINPUT,XBOPTS, moduleName) XBOPTS.Solution.value = 312 "Write deformed configuration to file" ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL312_def.dat' if XBOPTS.PrintInfo==True: sys.stdout.write('Writing file %s ... ' %(ofile)) fp = open(ofile,'w') fp.write('TITLE="Non-linear static solution: deformed geometry"\n') fp.write('VARIABLES="iElem" "iNode" "Px" "Py" "Pz" "Rx" "Ry" "Rz"\n') fp.close() if XBOPTS.PrintInfo==True: sys.stdout.write('done\n') WriteMode = 'a' BeamIO.OutputElems(XBINPUT.NumElems, NumNodes_tot.value, XBELEM, \ PosDefor, PsiDefor, ofile, WriteMode) "Initialise variables for dynamic analysis" Time, NumSteps, ForceTime, ForcedVel, ForcedVelDot,\ PosDotDef, PsiDotDef,\ OutGrids, PosPsiTime, VelocTime, DynOut\ = BeamInit.Dynamic(XBINPUT,XBOPTS, moduleName) # Delete unused vars del OutGrids, VelocTime "Write _force file" ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL312_force.dat' fp = open(ofile,'w') BeamIO.Write_force_File(fp, Time, ForceTime, ForcedVel, ForcedVelDot) fp.close() "Write _vel file" #TODO: write _vel file "Write .mrb file" #TODO: write .mrb file if XBOPTS.PrintInfo.value==True: sys.stdout.write('Solve nonlinear dynamic case in Python ... \n') "Initialise structural system tensors" MglobalFull = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F') CglobalFull = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F') KglobalFull = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F') FglobalFull = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F') Asys = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F') ms = ct.c_int() cs = ct.c_int() ks = ct.c_int() fs = ct.c_int() Mvel = np.zeros((NumDof.value,6), ct.c_double, 'F') Cvel = np.zeros((NumDof.value,6), ct.c_double, 'F') X = np.zeros(NumDof.value, ct.c_double, 'F') DX = np.zeros(NumDof.value, ct.c_double, 'F') dXdt = np.zeros(NumDof.value, ct.c_double, 'F') dXddt = np.zeros(NumDof.value, ct.c_double, 'F') Force_Dof = np.zeros(NumDof.value, ct.c_double, 'F') Qglobal = np.zeros(NumDof.value, ct.c_double, 'F') "Initialise rotation operators" Unit = np.zeros((3,3), ct.c_double, 'F') for i in range(3): Unit[i,i] = 1.0 Unit4 = np.zeros((4,4), ct.c_double, 'F') for i in range(4): Unit4[i,i] = 1.0 Cao = Unit.copy('F') Temp = Unit4.copy('F') Quat = np.zeros(4, ct.c_double, 'F') Quat[0] = 1.0 "Extract initial displacements and velocities" BeamLib.Cbeam_Solv_Disp2State(NumNodes_tot, NumDof, XBINPUT, XBNODE,\ PosDefor, PsiDefor, PosDotDef, PsiDotDef, X, dXdt) "Approximate initial accelerations" "Initialise accelerations as zero arrays" PosDotDotDef = np.zeros((NumNodes_tot.value,3),ct.c_double,'F') PsiDotDotDef = np.zeros((XBINPUT.NumElems,Settings.MaxElNod,3),\ ct.c_double, 'F') "Force at the first time-step" Force = (XBINPUT.ForceStatic + XBINPUT.ForceDyn*ForceTime[0]).copy('F') "Assemble matrices for dynamic analysis" BeamLib.Cbeam3_Asbly_Dynamic(XBINPUT, NumNodes_tot, XBELEM, XBNODE,\ PosIni, PsiIni, PosDefor, PsiDefor,\ PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef,\ Force, ForcedVel[0,:], ForcedVelDot[0,:],\ NumDof, Settings.DimMat,\ ms, MglobalFull, Mvel,\ cs, CglobalFull, Cvel,\ ks, KglobalFull, fs, FglobalFull,\ Qglobal, XBOPTS, Cao) "Get force vector for unconstrained nodes (Force_Dof)" BeamLib.f_fem_m2v(ct.byref(NumNodes_tot),\ ct.byref(ct.c_int(6)),\ Force.ctypes.data_as(ct.POINTER(ct.c_double)),\ ct.byref(NumDof),\ Force_Dof.ctypes.data_as(ct.POINTER(ct.c_double)),\ XBNODE.Vdof.ctypes.data_as(ct.POINTER(ct.c_int)) ) "Get RHS at initial condition" Qglobal += -np.dot(FglobalFull, Force_Dof) #Separate assembly of follower and dead loads" tmpForceTime=ForceTime[0].copy('F') Qforces = XbeamLib.LoadAssembly(XBINPUT, XBELEM, XBNODE, XBOPTS, NumDof, \ PosIni, PsiIni, PosDefor, PsiDefor, \ (XBINPUT.ForceStatic_foll + XBINPUT.ForceDyn_foll*tmpForceTime), \ (XBINPUT.ForceStatic_dead + XBINPUT.ForceDyn_dead*tmpForceTime), \ Cao, 1)[0] Qglobal -= Qforces "Initial Accel" dXddt[:] = np.dot(np.linalg.inv(MglobalFull), -Qglobal) "Record position of all grid points in global FoR at initial time step" DynOut[0:NumNodes_tot.value,:] = PosDefor "Position/rotation of the selected node in initial deformed configuration" PosPsiTime[0,:3] = PosDefor[-1,:] PosPsiTime[0,3:] = PsiDefor[-1,XBELEM.NumNodes[-1]-1,:] "Get gamma and beta for Newmark scheme" gamma = 0.5 + XBOPTS.NewmarkDamp.value beta = 0.25*np.power((gamma + 0.5),2.0) "Time loop" for iStep in range(NumSteps.value): if XBOPTS.PrintInfo.value==True: sys.stdout.write(' Time: %-10.4e\n' %(Time[iStep+1])) sys.stdout.write(' SubIter DeltaF DeltaX ResLog10\n') "calculate dt" dt = Time[iStep+1] - Time[iStep] "Update transformation matrix for given angular velocity" Temp = np.linalg.inv(Unit4 + 0.25*XbeamLib.QuadSkew(ForcedVel[iStep+1,3:])*dt) Quat = np.dot(Temp, np.dot(Unit4 - 0.25*XbeamLib.QuadSkew(ForcedVel[iStep,3:])*dt, Quat)) Quat = Quat/np.linalg.norm(Quat) Cao = XbeamLib.Rot(Quat) "Predictor step" X += dt*dXdt + (0.5-beta)*dXddt*dt**2 dXdt += (1.0-gamma)*dXddt*dt dXddt[:] = 0.0 "Force at current time-step" Force = (XBINPUT.ForceStatic + \ XBINPUT.ForceDyn*ForceTime[iStep+1]).copy('F') "Reset convergence parameters" Iter = 0 ResLog10 = 1.0 "Newton-Raphson loop" while ( (ResLog10 > XBOPTS.MinDelta.value) \ & (Iter < XBOPTS.MaxIterations.value) ): "set tensors to zero" Qglobal[:] = 0.0 Mvel[:,:] = 0.0 Cvel[:,:] = 0.0 MglobalFull[:,:] = 0.0 CglobalFull[:,:] = 0.0 KglobalFull[:,:] = 0.0 FglobalFull[:,:] = 0.0 "Update counter" Iter += 1 if XBOPTS.PrintInfo.value==True: sys.stdout.write(' %-7d ' %(Iter)) "nodal diplacements and velocities from state vector" BeamLib.Cbeam3_Solv_State2Disp(XBINPUT, NumNodes_tot, XBELEM, XBNODE, PosIni, PsiIni, NumDof, X, dXdt,\ PosDefor, PsiDefor, PosDotDef, PsiDotDef) "update matrices" BeamLib.Cbeam3_Asbly_Dynamic(XBINPUT, NumNodes_tot, XBELEM, XBNODE,\ PosIni, PsiIni, PosDefor, PsiDefor,\ PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef,\ Force, ForcedVel[iStep+1,:], ForcedVelDot[iStep+1,:],\ NumDof, Settings.DimMat,\ ms, MglobalFull, Mvel,\ cs, CglobalFull, Cvel,\ ks, KglobalFull, fs, FglobalFull,\ Qglobal, XBOPTS, Cao) "Get force vector for unconstrained nodes (Force_Dof)" BeamLib.f_fem_m2v(ct.byref(NumNodes_tot),\ ct.byref(ct.c_int(6)),\ Force.ctypes.data_as(ct.POINTER(ct.c_double)),\ ct.byref(NumDof),\ Force_Dof.ctypes.data_as(ct.POINTER(ct.c_double)),\ XBNODE.Vdof.ctypes.data_as(ct.POINTER(ct.c_int)) ) "Solve for update vector" "Residual" Qglobal += np.dot(MglobalFull, dXddt) \ + np.dot(Mvel,ForcedVelDot[iStep+1,:]) \ - np.dot(FglobalFull, Force_Dof) #Separate assembly of follower and dead loads tmpForceTime=ForceTime[iStep+1].copy('F') Qforces = XbeamLib.LoadAssembly(XBINPUT, XBELEM, XBNODE, XBOPTS, NumDof, \ PosIni, PsiIni, PosDefor, PsiDefor, \ (XBINPUT.ForceStatic_foll + XBINPUT.ForceDyn_foll*tmpForceTime), \ (XBINPUT.ForceStatic_dead + XBINPUT.ForceDyn_dead*tmpForceTime), \ Cao,1)[0] Qglobal -= Qforces if XBOPTS.PrintInfo.value==True: sys.stdout.write('%-10.4e ' %(max(abs(Qglobal)))) "Calculate system matrix for update calculation" Asys = KglobalFull + \ CglobalFull*gamma/(beta*dt) + \ MglobalFull/(beta*np.power(dt,2.0)) "Solve for update" DX[:] = np.dot(np.linalg.inv(Asys), -Qglobal) "Corrector step" X += DX dXdt += DX*gamma/(beta*dt) dXddt += DX/(beta*dt**2) "Residual at first iteration" if(Iter == 1): Res0_Qglobal = max(max(abs(Qglobal)),1) Res0_DeltaX = max(max(abs(DX)),1) "Update residual and compute log10" Res_Qglobal = max(abs(Qglobal)) Res_DeltaX = max(abs(DX)) ResLog10 = max(Res_Qglobal/Res0_Qglobal,Res_DeltaX/Res0_DeltaX) if XBOPTS.PrintInfo.value==True: sys.stdout.write('%-10.4e %8.4f\n' %(max(abs(DX)),ResLog10)) "END Netwon-Raphson" "update to converged nodal displacements and velocities" BeamLib.Cbeam3_Solv_State2Disp(XBINPUT, NumNodes_tot, XBELEM, XBNODE, PosIni, PsiIni, NumDof, X, dXdt, PosDefor, PsiDefor, PosDotDef, PsiDotDef) PosPsiTime[iStep+1,:3] = PosDefor[(NumNodes_tot.value-1)/2+1,:] PosPsiTime[iStep+1,3:] = PsiDefor[-1,XBELEM.NumNodes[-1]-1,:] "Position of all grid points in global FoR" i1 = (iStep+1)*NumNodes_tot.value i2 = (iStep+2)*NumNodes_tot.value DynOut[i1:i2,:] = PosDefor "END Time loop" "Write _dyn file" ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL312_dyn.dat' fp = open(ofile,'w') BeamIO.Write_dyn_File(fp, Time, PosPsiTime) fp.close() "Write _shape file" ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL312_shape.dat' fp = open(ofile,'w') BeamIO.Write_shape_File(fp, len(Time), NumNodes_tot.value, Time, DynOut) fp.close() if XBOPTS.PrintInfo.value==True: sys.stdout.write(' ... done\n')
def Solve_Py(XBINPUT,XBOPTS,VMOPTS,VMINPUT,AELAOPTS,**kwords): """@brief Nonlinear dynamic solver using Python to solve aeroelastic equation. @details Assembly of structural matrices is carried out with Fortran subroutines. Aerodynamics solved using PyAero\.UVLM. @param XBINPUT Beam inputs (for initialization in Python). @param XBOPTS Beam solver options (for Fortran). @param VMOPTS UVLM solver options (for C/C++). @param VMINPUT UVLM solver inputs (for initialization in Python). @param VMUNST Unsteady input information for aero solver. @param AELAOPTS Options relevant to coupled aeroelastic simulations. @param writeDict OrderedDict of 'name':tuple of outputs to write. """ # Check correct solution code. assert XBOPTS.Solution.value == 912, ('NonlinearFlightDynamic requested' + ' with wrong solution code') # I/O management XBOUT=DerivedTypes.Xboutput() SaveDict=Settings.SaveDict if 'SaveDict' in kwords: SaveDict=kwords['SaveDict'] if SaveDict['Format']=='h5': Settings.WriteOut=False Settings.PlotTec=False OutList=[AELAOPTS, VMINPUT, VMOPTS, XBOPTS, XBINPUT, XBOUT] #if VMINPUT.ctrlSurf!=None: # for cc in range(len(VMINPUT.ctrlSurf)): # OutList.append(VMINPUT.ctrlSurf[cc]) if SaveDict['SaveWake'] is True: dirwake=SaveDict['OutputDir']+'wake'+SaveDict['OutputFileRoot']+'/' os.system('mkdir -p %s' %dirwake) XBOUT.dirwake=dirwake XBOUT.cputime.append(time.clock()) # time.processor_time more appropriate but equivalent # for debugging XBOUT.ForceDofList=[] XBOUT.ForceRigidList=[] # Initialise static beam data. XBINPUT, XBOPTS, NumNodes_tot, XBELEM, PosIni, PsiIni, XBNODE, NumDof \ = BeamInit.Static(XBINPUT,XBOPTS) # special BCs SphFlag=False if XBNODE.Sflag.any(): SphFlag=True # Debugging Flags if 'HardCodeAero' in kwords: HardCodeAero=kwords['HardCodeAero'] SaveExtraVariables = False #------------------------- Initial Displacement: ImpStart vs Static Solution # Calculate initial displacements. if AELAOPTS.ImpStart == False: XBOPTS.Solution.value = 112 # Modify options. VMOPTS.Steady = ct.c_bool(True) Rollup = VMOPTS.Rollup.value VMOPTS.Rollup.value = False # Solve Static Aeroelastic. PosDefor, PsiDefor, Zeta, ZetaStar, Gamma, GammaStar, Force = \ Static.Solve_Py(XBINPUT, XBOPTS, VMOPTS, VMINPUT, AELAOPTS) XBOPTS.Solution.value = 912 # Reset options. VMOPTS.Steady = ct.c_bool(False) VMOPTS.Rollup.value = Rollup elif AELAOPTS.ImpStart == True: PosDefor = PosIni.copy(order='F') PsiDefor = PsiIni.copy(order='F') Force = np.zeros((XBINPUT.NumNodesTot,6),ct.c_double,'F') if SaveDict['Format']!='h5': write_SOL912_def(XBOPTS,XBINPUT,XBELEM,NumNodes_tot,PosDefor,PsiDefor,SaveDict) else: XBOUT.PosDeforStatic=PosDefor.copy() XBOUT.PsiDeforStatic=PsiDefor.copy() XBOUT.ForceTotStatic = Force.copy() #------------------------------------------------ Initialise Dynamic Problem # Initialise structural variables for dynamic analysis. Time, NumSteps, ForceTime, Vrel, VrelDot,\ PosDotDef, PsiDotDef,\ OutGrids, PosPsiTime, VelocTime, DynOut\ = BeamInit.Dynamic(XBINPUT,XBOPTS) # Delete unused variables. del OutGrids, VelocTime # sm I/O ### why forced velocity with Sol912 ??? ### If forced velocities are prescribed, then is Sol312 XBOUT.PosDefor=PosDefor # ...SOL912_def.dat XBOUT.PsiDefor=PsiDefor XBOUT.ForceTime_force=ForceTime # ...SOL912_force.dat XBOUT.Vrel_force=Vrel XBOUT.VrelDot_force=VrelDot if XBOPTS.PrintInfo.value==True: sys.stdout.write('Solve nonlinear dynamic case in Python ... \n') #------------------------------------------------------ Initialise Variables #Initialise structural system tensors MssFull = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F') CssFull = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F') KssFull = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F') FstrucFull = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F') ms = ct.c_int() cs = ct.c_int() ks = ct.c_int() fs = ct.c_int() Msr = np.zeros((NumDof.value,6), ct.c_double, 'F') Csr = np.zeros((NumDof.value,6), ct.c_double, 'F') X = np.zeros(NumDof.value, ct.c_double, 'F') dXdt = np.zeros(NumDof.value, ct.c_double, 'F') Force_Dof = np.zeros(NumDof.value, ct.c_double, 'F') Qstruc = np.zeros(NumDof.value, ct.c_double, 'F') #Initialise rigid-body system tensors MrsFull = np.zeros((6,NumDof.value), ct.c_double, 'F') CrsFull = np.zeros((6,NumDof.value), ct.c_double, 'F') KrsFull = np.zeros((6,NumDof.value), ct.c_double, 'F') FrigidFull = np.zeros((6,NumDof.value+6), ct.c_double, 'F') mr = ct.c_int() cr = ct.c_int() kr = ct.c_int() fr = ct.c_int() Mrr = np.zeros((6,6), ct.c_double, 'F') Crr = np.zeros((6,6), ct.c_double, 'F') Qrigid = np.zeros(6, ct.c_double, 'F') #Initialise full system tensors Q = np.zeros(NumDof.value+6+4, ct.c_double, 'F') DQ = np.zeros(NumDof.value+6+4, ct.c_double, 'F') dQdt = np.zeros(NumDof.value+6+4, ct.c_double, 'F') dQddt = np.zeros(NumDof.value+6+4, ct.c_double, 'F') Force_All = np.zeros(NumDof.value+6, ct.c_double, 'F') Msys = np.zeros((NumDof.value+6+4,NumDof.value+6+4), ct.c_double, 'F') Csys = np.zeros((NumDof.value+6+4,NumDof.value+6+4), ct.c_double, 'F') Ksys = np.zeros((NumDof.value+6+4,NumDof.value+6+4), ct.c_double, 'F') Asys = np.zeros((NumDof.value+6+4,NumDof.value+6+4), ct.c_double, 'F') Qsys = np.zeros(NumDof.value+6+4, ct.c_double, 'F') #---------------------------------------------------- Start Dynamic Solution #Initialise rotation operators. TODO: include initial AOA here currVrel=Vrel[0,:].copy('F') # Initialise attitude: Quat = xbl.psi2quat(XBINPUT.PsiA_G) #Quat= XBINPUT.quat0 #### sm debug XBOUT.Quat0=Quat XBOUT.currVel0=currVrel Cao = xbl.Rot(Quat) ACoa = np.zeros((6,6), ct.c_double, 'F') ACoa[:3,:3] = np.transpose(Cao) ACoa[3:,3:] = np.transpose(Cao) Cqr = np.zeros((4,6), ct.c_double, 'F') Cqq = np.zeros((4,4), ct.c_double, 'F') Unit4 = np.zeros((4,4), ct.c_double, 'F') for i in range(4): Unit4[i,i] = 1.0 # Extract initial displacements and velocities. BeamLib.Cbeam_Solv_Disp2State(NumNodes_tot, NumDof, XBINPUT, XBNODE, PosDefor, PsiDefor, PosDotDef, PsiDotDef, X, dXdt) # Approximate initial accelerations. PosDotDotDef = np.zeros((NumNodes_tot.value,3),ct.c_double,'F') PsiDotDotDef = np.zeros((XBINPUT.NumElems,Settings.MaxElNod,3), ct.c_double, 'F') #Populate state vector Q[:NumDof.value]=X.copy('F') dQdt[:NumDof.value]=dXdt.copy('F') dQdt[NumDof.value:NumDof.value+6] = Vrel[0,:].copy('F') dQdt[NumDof.value+6:]= Quat.copy('F') #Force at the first time-step #Force += (XBINPUT.ForceDyn*ForceTime[0]).copy('F') Force += (XBINPUT.ForceDyn[0,:,:]).copy('F') #Assemble matrices and loads for structural dynamic analysis currVrel=Vrel[0,:].copy('F') tmpQuat=Quat.copy('F') BeamLib.Cbeam3_Asbly_Dynamic(XBINPUT, NumNodes_tot, XBELEM, XBNODE, PosIni, PsiIni, PosDefor, PsiDefor, PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef, Force, currVrel, 0*currVrel, NumDof, Settings.DimMat, ms, MssFull, Msr, cs, CssFull, Csr, ks, KssFull, fs, FstrucFull, Qstruc, XBOPTS, Cao) BeamLib.f_fem_m2v(ct.byref(NumNodes_tot), ct.byref(ct.c_int(6)), Force.ctypes.data_as(ct.POINTER(ct.c_double)), ct.byref(NumDof), Force_Dof.ctypes.data_as(ct.POINTER(ct.c_double)), XBNODE.Vdof.ctypes.data_as(ct.POINTER(ct.c_int)) ) Qstruc -= np.dot(FstrucFull, Force_Dof) #Assemble matrices for rigid-body dynamic analysis BeamLib.Xbeam_Asbly_Dynamic(XBINPUT, NumNodes_tot, XBELEM, XBNODE, PosIni, PsiIni, PosDefor, PsiDefor, PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef, currVrel, 0*currVrel, tmpQuat, NumDof, Settings.DimMat, mr, MrsFull, Mrr, cr, CrsFull, Crr, Cqr, Cqq, kr, KrsFull, fr, FrigidFull, Qrigid, XBOPTS, Cao) BeamLib.f_fem_m2v_nofilter(ct.byref(NumNodes_tot), ct.byref(ct.c_int(6)), Force.ctypes.data_as(ct.POINTER(ct.c_double)), ct.byref(ct.c_int(NumDof.value+6)), Force_All.ctypes.data_as(ct.POINTER(ct.c_double)) ) Qrigid -= np.dot(FrigidFull, Force_All) # #Separate assembly of follower and dead loads # tmpForceTime=ForceTime[0].copy('F') # tmpQforces,Dummy,tmpQrigid = xbl.LoadAssembly(XBINPUT, XBELEM, XBNODE, XBOPTS, NumDof, # PosIni, PsiIni, PosDefor, PsiDefor, # (XBINPUT.ForceStatic_foll + XBINPUT.ForceDyn_foll*tmpForceTime), # (XBINPUT.ForceStatic_dead + XBINPUT.ForceDyn_dead*tmpForceTime), # Cao,1) # # Qstruc -= tmpQforces # Qrigid -= tmpQrigid #Assemble system matrices Msys[:NumDof.value,:NumDof.value] = MssFull.copy('F') Msys[:NumDof.value,NumDof.value:NumDof.value+6] = Msr.copy('F') Msys[NumDof.value:NumDof.value+6,:NumDof.value] = MrsFull.copy('F') Msys[NumDof.value:NumDof.value+6,NumDof.value:NumDof.value+6] = Mrr.copy('F') Msys[NumDof.value+6:,NumDof.value+6:] = Unit4.copy('F') Qsys[:NumDof.value] = Qstruc Qsys[NumDof.value:NumDof.value+6] = Qrigid Qsys[NumDof.value+6:] = np.dot(Cqq,dQdt[NumDof.value+6:]) # special BCs if SphFlag: # block translations iiblock = [ ii for ii in range(NumDof.value,NumDof.value+3) ] # block rotations iifree=[] # free rotational dof for ii in range(3): if XBINPUT.EnforceAngVel_FoRA[ii] is True: iiblock.append(NumDof.value+3+ii) else: iifree.append(NumDof.value+3+ii) # block dof Msys[iiblock,:] = 0.0 Msys[iiblock,iiblock] = 1.0 Qsys[iiblock] = 0.0 # add damp at the spherical joints if XBINPUT.sph_joint_damping is not None: Qsys[iifree]+= XBINPUT.sph_joint_damping*dQdt[iifree] # add structural damping term if XBINPUT.str_damping_model is not None: Cdamp = XBINPUT.str_damping_param['alpha'] * MssFull + \ XBINPUT.str_damping_param['beta'] * KssFull Qsys[:NumDof.value] += np.dot( Cdamp, dQdt[:NumDof.value] ) pass #store initial matrices for eigenvalues analysis XBOUT.MssFull0 = MssFull.copy() XBOUT.CssFull0 = CssFull.copy() XBOUT.KssFull0 = KssFull.copy() # Initial Accel. ###dQddt[:] = np.dot(np.linalg.inv(Msys), -Qsys) dQddt[:] = np.linalg.solve(Msys,-Qsys) XBOUT.dQddt0=dQddt.copy() #Record position of all grid points in global FoR at initial time step DynOut[0:NumNodes_tot.value,:] = PosDefor #Position/rotation of the selected node in initial deformed configuration PosPsiTime[0,:3] = PosDefor[-1,:] PosPsiTime[0,3:] = PsiDefor[-1,XBELEM.NumNodes[-1]-1,:] #Get gamma and beta for Newmark scheme gamma = 0.5 + XBOPTS.NewmarkDamp.value beta = 0.25*(gamma + 0.5)**2 #---------------------------------------------- Initialise Aerodynamic Force # Initialise Aero Section = InitSection(VMOPTS,VMINPUT,AELAOPTS.ElasticAxis) # Declare memory for Aero variables. ZetaDot = np.zeros((Section.shape[0],PosDefor.shape[0],3),ct.c_double,'C') K = VMOPTS.M.value*VMOPTS.N.value AIC = np.zeros((K,K),ct.c_double,'C') BIC = np.zeros((K,K),ct.c_double,'C') AeroForces = np.zeros((VMOPTS.M.value+1,VMOPTS.N.value+1,3),ct.c_double,'C') # Initialise A-frame location and orientation to be zero. OriginA_a = np.zeros(3,ct.c_double,'C') PsiA_G = XBINPUT.PsiA_G.copy() #xbl.quat2psi(Quat) # CRV at iStep # Init external velocities. Ufree = InitSteadyExternalVels(VMOPTS,VMINPUT) if AELAOPTS.ImpStart == True: Zeta = np.zeros((Section.shape[0],PosDefor.shape[0],3),ct.c_double,'C') Gamma = np.zeros((VMOPTS.M.value,VMOPTS.N.value),ct.c_double,'C') # Generate surface, wake and gamma matrices. CoincidentGrid(PosDefor, PsiDefor, Section, currVrel[:3], currVrel[3:], PosDotDef, PsiDotDef, XBINPUT, Zeta, ZetaDot, OriginA_a, PsiA_G, VMINPUT.ctrlSurf) # init wake grid and gamma matrix. ZetaStar, GammaStar = InitSteadyWake(VMOPTS,VMINPUT,Zeta,currVrel[:3]) # sm save #XBOUT.Zeta0 = Zeta.copy('C') #XBOUT.ZetaStar0 = ZetaStar.copy('C') #XBOUT.ZetaStarList.append(np.float32( ZetaStar.copy('C') )) # Define TecPlot stuff if Settings.PlotTec==True: FileObject=write_TecPlot(Zeta, ZetaStar, Gamma, GammaStar, NumSteps.value, 0, Time[0], SaveDict) if 'writeDict' in kwords and Settings.WriteOut == True: fp= write_SOL912_out(Time[0], PosDefor, PsiDefor, PosIni, PsiIni, XBELEM, kwords['writeDict'], SaveDict) # sm write class XBOUT.QuatList.append(Quat.copy()) XBOUT.CRVList.append(PsiA_G) XBOUT.PosIni=PosIni XBOUT.PsiIni=PsiIni XBOUT.AsysListStart=[] XBOUT.AsysListEnd=[] XBOUT.MsysList=[] XBOUT.CsysList=[] XBOUT.KsysList=[] #---------------------------------------------------------------- Time loop for iStep in range(NumSteps.value): if XBOPTS.PrintInfo.value==True: sys.stdout.write('Time: %-10.4e\n' %(Time[iStep+1])) sys.stdout.write(' SubIter DeltaF DeltaX ResLog10\n') #calculate dt dt = Time[iStep+1] - Time[iStep] # Set dt for aero force calcs. VMOPTS.DelTime = ct.c_double(dt) #Predictor step Q += dt*dQdt + (0.5-beta)*dQddt*np.power(dt,2.0) dQdt += (1.0-gamma)*dQddt*dt dQddt[:] = 0.0 # Quaternion update for orientation. Quat = dQdt[NumDof.value+6:].copy('F') Quat = Quat/np.linalg.norm(Quat) Cao = xbl.Rot(Quat) #nodal displacements and velocities from state vector X=Q[:NumDof.value].copy('F') dXdt=dQdt[:NumDof.value].copy('F'); BeamLib.Cbeam3_Solv_State2Disp(XBINPUT,NumNodes_tot,XBELEM,XBNODE, PosIni,PsiIni,NumDof,X,dXdt, PosDefor,PsiDefor,PosDotDef,PsiDotDef) #------------------------------------------------------- Aero Force Loop # Force at current time-step. TODO: Check communication flow. if iStep > 0 and AELAOPTS.Tight == False: # zero aero forces. AeroForces[:,:,:] = 0.0 # Update CRV. PsiA_G = xbl.quat2psi(Quat) # CRV at iStep # Update origin. # sm: origin position projected in FoR A currVrel=Vrel[iStep-1,:].copy('F') OriginA_a[:] = OriginA_a[:] + currVrel[:3]*dt #sm: OriginA_a initialised to zero # Update control surface deflection. if VMINPUT.ctrlSurf != None: # open-loop control for cc in range(len(VMINPUT.ctrlSurf)): VMINPUT.ctrlSurf[cc].update(Time[iStep],iStep=iStep) # Generate surface grid. currVrel=Vrel[iStep,:].copy('F') CoincidentGrid(PosDefor, PsiDefor, Section, currVrel[:3], currVrel[3:], PosDotDef, PsiDotDef, XBINPUT, Zeta, ZetaDot, OriginA_a, PsiA_G, VMINPUT.ctrlSurf) # Update wake geom #'roll' data. ZetaStar = np.roll(ZetaStar,1,axis = 0) GammaStar = np.roll(GammaStar,1,axis = 0) #overwrite grid points with TE. ZetaStar[0,:] = Zeta[VMOPTS.M.value,:] # overwrite Gamma with TE value from previous timestep. GammaStar[0,:] = Gamma[VMOPTS.M.value-1,:] # Apply gust velocity. if VMINPUT.gust != None: Utot = Ufree + VMINPUT.gust.Vels(Zeta) else: Utot = Ufree # Solve for AeroForces UVLMLib.Cpp_Solver_VLM(Zeta, ZetaDot, Utot, ZetaStar, VMOPTS, AeroForces, Gamma, GammaStar, AIC, BIC) # Apply density scaling AeroForces[:,:,:] = AELAOPTS.AirDensity*AeroForces[:,:,:] if Settings.PlotTec==True: FileObject=write_TecPlot(Zeta, ZetaStar, Gamma, GammaStar, NumSteps.value, iStep, Time[iStep], SaveDict,FileObject=FileObject) # map AeroForces to beam. CoincidentGridForce(XBINPUT, PsiDefor, Section, AeroForces, Force, PsiA_G) ForceAero = Force.copy('C') # Add gravity loads. AddGravityLoads(Force, XBINPUT, XBELEM, AELAOPTS, PsiDefor, VMINPUT.c) # Add thrust and other point loads #Force += (XBINPUT.ForceStatic + XBINPUT.ForceDyn*ForceTime[iStep+1]).copy('F') Force += (XBINPUT.ForceStatic + XBINPUT.ForceDyn[iStep+1,:,:]).copy('F') # sm: here to avoid crash at first time-step XBOUT.ForceAeroList.append(ForceAero.copy('C')) #END if iStep > 0 # sm: save aero data if ( SaveDict['SaveWake']==True and iStep%SaveDict['SaveWakeFreq'] == 0 ): nfile=iStep//SaveDict['SaveWakeFreq'] hdwake=h5py.File(dirwake+'%.4d.h5'%nfile,'w') hdwake['iStep']=iStep hdwake['Zeta']= np.float32(Zeta.copy('C')) hdwake['ZetaStar']= np.float32(ZetaStar.copy('C')) hdwake.close() #XBOUT.ZetaList.append( np.float32(Zeta.copy('C')) ) #XBOUT.ZetaStarList.append( np.float32(ZetaStar.copy('C')) ) #XBOUT.GammaStarList.append(GammaStar.copy('C')) #XBOUT.GammaList.append(Gamma.copy('C')) #Reset convergence parameters Iter = 0 ResLog10 = 1.0 #Newton-Raphson loop while ( (ResLog10 > XBOPTS.MinDelta.value) & (Iter < XBOPTS.MaxIterations.value) ): #set tensors to zero MssFull[:,:] = 0.0; CssFull[:,:] = 0.0 KssFull[:,:] = 0.0; FstrucFull[:,:] = 0.0 Msr[:,:] = 0.0; Csr[:,:] = 0.0 Qstruc[:] = 0.0 MrsFull[:,:] = 0.0; CrsFull[:,:] = 0.0 KrsFull[:,:] = 0.0; FrigidFull[:,:] = 0.0 Mrr[:,:] = 0.0; Crr[:,:] = 0.0 Qrigid[:] = 0.0 Msys[:,:] = 0.0; Csys[:,:] = 0.0 Ksys[:,:] = 0.0; Asys[:,:] = 0.0 Qsys[:] = 0.0 # Update counter. Iter += 1 if XBOPTS.PrintInfo.value==True: sys.stdout.write(' %-7d ' %(Iter)) # Nodal displacements and velocities from state vector X=Q[:NumDof.value].copy('F') dXdt=dQdt[:NumDof.value].copy('F'); BeamLib.Cbeam3_Solv_State2Disp(XBINPUT, NumNodes_tot, XBELEM, XBNODE, PosIni, PsiIni, NumDof, X, dXdt, PosDefor, PsiDefor, PosDotDef, PsiDotDef) #rigid-body velocities and orientation from state vector Vrel[iStep+1,:] = dQdt[NumDof.value:NumDof.value+6].copy('F') VrelDot[iStep+1,:] = dQddt[NumDof.value:NumDof.value+6].copy('F') Quat = dQdt[NumDof.value+6:].copy('F') Quat = Quat/np.linalg.norm(Quat) Cao = xbl.Rot(Quat) #Update matrices and loads for structural dynamic analysis tmpVrel=Vrel[iStep+1,:].copy('F') tmpQuat=Quat.copy('F') BeamLib.Cbeam3_Asbly_Dynamic(XBINPUT, NumNodes_tot, XBELEM, XBNODE, PosIni, PsiIni, PosDefor, PsiDefor, PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef, Force, tmpVrel, 0*tmpVrel, NumDof, Settings.DimMat, ms, MssFull, Msr, cs, CssFull, Csr, ks, KssFull, fs, FstrucFull, Qstruc, XBOPTS, Cao) BeamLib.f_fem_m2v(ct.byref(NumNodes_tot), ct.byref(ct.c_int(6)), Force.ctypes.data_as(ct.POINTER(ct.c_double)), ct.byref(NumDof), Force_Dof.ctypes.data_as(ct.POINTER(ct.c_double)), XBNODE.Vdof.ctypes.data_as(ct.POINTER(ct.c_int)) ) #Update matrices for rigid-body dynamic analysis BeamLib.Xbeam_Asbly_Dynamic(XBINPUT, NumNodes_tot, XBELEM, XBNODE, PosIni, PsiIni, PosDefor, PsiDefor, PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef, tmpVrel, 0*tmpVrel, tmpQuat, NumDof, Settings.DimMat, mr, MrsFull, Mrr, cr, CrsFull, Crr, Cqr, Cqq, kr, KrsFull, fs, FrigidFull, Qrigid, XBOPTS, Cao) BeamLib.f_fem_m2v_nofilter(ct.byref(NumNodes_tot), ct.byref(ct.c_int(6)), Force.ctypes.data_as(ct.POINTER(ct.c_double)), ct.byref(ct.c_int(NumDof.value+6)), Force_All.ctypes.data_as(ct.POINTER(ct.c_double)) ) #Residual at first iteration if(Iter == 1): Res0_Qglobal = max(max(abs(Qsys)),1) Res0_DeltaX = max(max(abs(DQ)),1) #Assemble discrete system matrices with linearised quaternion equations Msys[:NumDof.value,:NumDof.value] = MssFull.copy('F') Msys[:NumDof.value,NumDof.value:NumDof.value+6] = Msr.copy('F') Msys[NumDof.value:NumDof.value+6,:NumDof.value] = MrsFull.copy('F') Msys[NumDof.value:NumDof.value+6,NumDof.value:NumDof.value+6] = Mrr.copy('F') Msys[NumDof.value+6:,NumDof.value+6:] = Unit4.copy('F') Csys[:NumDof.value,:NumDof.value] = CssFull.copy('F') Csys[:NumDof.value,NumDof.value:NumDof.value+6] = Csr.copy('F') Csys[NumDof.value:NumDof.value+6,:NumDof.value] = CrsFull.copy('F') Csys[NumDof.value:NumDof.value+6,NumDof.value:NumDof.value+6] = Crr.copy('F') Csys[NumDof.value+6:,NumDof.value:NumDof.value+6] = Cqr.copy('F') Csys[NumDof.value+6:,NumDof.value+6:] = Cqq.copy('F') Ksys[:NumDof.value,:NumDof.value] = KssFull.copy('F') Ksys[NumDof.value:NumDof.value+6,:NumDof.value] = KrsFull.copy('F') # #Separate assembly of follower and dead loads # tmpForceTime=ForceTime[iStep+1].copy('F') # tmpQforces,Dummy,tmpQrigid = xbl.LoadAssembly(XBINPUT, XBELEM, XBNODE, XBOPTS, NumDof, \ # PosIni, PsiIni, PosDefor, PsiDefor, \ # (XBINPUT.ForceStatic_foll + XBINPUT.ForceDyn_foll*tmpForceTime), \ # (XBINPUT.ForceStatic_dead + XBINPUT.ForceDyn_dead*tmpForceTime), \ # Cao,1) # # Qstruc -= tmpQforces # Qrigid -= tmpQrigid #Compute residual to solve update vector Qstruc += -np.dot(FstrucFull, Force_Dof) Qrigid += -np.dot(FrigidFull, Force_All) Qsys[:NumDof.value] = Qstruc Qsys[NumDof.value:NumDof.value+6] = Qrigid Qsys[NumDof.value+6:] = np.dot(Cqq,dQdt[NumDof.value+6:]) Qsys += np.dot(Msys,dQddt) # include damping if XBINPUT.str_damping_model == 'prop': Cdamp = XBINPUT.str_damping_param['alpha'] * MssFull + \ XBINPUT.str_damping_param['beta'] * KssFull Csys[:NumDof.value,:NumDof.value] += Cdamp Qsys[:NumDof.value] += np.dot(Cdamp, dQdt[:NumDof.value]) # special BCs if SphFlag: Msys[iiblock,:] = 0.0 Msys[iiblock,iiblock] = 1.0 Csys[iiblock,:] = 0.0 Ksys[iiblock,:] = 0.0 Qsys[iiblock] = 0.0 if XBINPUT.sph_joint_damping is not None: Csys[iifree,iifree] += XBINPUT.sph_joint_damping Qsys[iifree] += XBINPUT.sph_joint_damping*dQdt[iifree] #Calculate system matrix for update calculation Asys = Ksys + Csys*gamma/(beta*dt) + Msys/(beta*dt**2) #Compute correction ###DQ[:] = np.dot(np.linalg.inv(Asys), -Qsys) DQ[:] = np.linalg.solve(Asys,-Qsys) Q += DQ dQdt += DQ*gamma/(beta*dt) dQddt += DQ/(beta*dt**2) #Update convergence criteria if XBOPTS.PrintInfo.value==True: sys.stdout.write('%-10.4e ' %(max(abs(Qsys)))) Res_Qglobal = max(abs(Qsys)) Res_DeltaX = max(abs(DQ)) ResLog10 = max(Res_Qglobal/Res0_Qglobal,Res_DeltaX/Res0_DeltaX) if XBOPTS.PrintInfo.value==True: sys.stdout.write('%-10.4e %8.4f\n' %(max(abs(DQ)),ResLog10)) if SaveExtraVariables is True: if Iter == 1: XBOUT.AsysListStart.append(Asys.copy()) if ( (ResLog10 < XBOPTS.MinDelta.value) or (Iter >= XBOPTS.MaxIterations.value) ): XBOUT.AsysListEnd.append(Asys.copy()) XBOUT.MsysList.append(Msys.copy()) XBOUT.CsysList.append(Csys.copy()) XBOUT.KsysList.append(Ksys.copy()) # END Netwon-Raphson. # sm debug: # save forcing terms: XBOUT.ForceDofList.append( np.dot(FstrucFull, Force_Dof).copy() ) XBOUT.ForceRigidList.append( np.dot(FrigidFull, Force_All).copy() ) #update to converged nodal displacements and velocities X=Q[:NumDof.value].copy('F') dXdt=dQdt[:NumDof.value].copy('F'); BeamLib.Cbeam3_Solv_State2Disp(XBINPUT, NumNodes_tot, XBELEM, XBNODE, PosIni, PsiIni, NumDof, X, dXdt,\ PosDefor, PsiDefor, PosDotDef, PsiDotDef) PosPsiTime[iStep+1,:3] = PosDefor[-1,:] PosPsiTime[iStep+1,3:] = PsiDefor[-1,XBELEM.NumNodes[-1]-1,:] #Position of all grid points in global FoR i1 = (iStep+1)*NumNodes_tot.value i2 = (iStep+2)*NumNodes_tot.value DynOut[i1:i2,:] = PosDefor #Export rigid-body velocities/accelerations if XBOPTS.OutInaframe.value==True: Vrel[iStep,:] = dQdt[NumDof.value:NumDof.value+6].copy('F') VrelDot[iStep,:] = dQddt[NumDof.value:NumDof.value+6].copy('F') else: Quat = dQdt[NumDof.value+6:].copy('F') Quat = Quat/np.linalg.norm(Quat) Cao = xbl.Rot(Quat) ACoa[:3,:3] = np.transpose(Cao) ACoa[3:,3:] = np.transpose(Cao) Vrel[iStep,:] = np.dot(ACoa,dQdt[NumDof.value:NumDof.value+6].copy('F')) VrelDot[iStep,:] = np.dot(ACoa,dQddt[NumDof.value:NumDof.value+6].copy('F')) if 'writeDict' in kwords and Settings.WriteOut == True: fp= write_SOL912_out(Time[iStep+1], PosDefor, PsiDefor, PosIni, PsiIni, XBELEM, kwords['writeDict'], SaveDict, FileObject=fp) # 'Rollup' due to external velocities. TODO: Must add gusts here! ZetaStar[:,:] = ZetaStar[:,:] + VMINPUT.U_infty*dt # sm: append outputs XBOUT.QuatList.append(Quat.copy()) XBOUT.CRVList.append(PsiA_G.copy()) # sm I/O: FoR A velocities/accelerations XBOUT.Time=Time # ...dyn.dat #XBOUT.PosPsiTime = PosPsiTime XBOUT.DynOut=DynOut # ...shape.dat XBOUT.Vrel=Vrel # ...rigid.dat XBOUT.VrelDot=VrelDot #XBOUT.PosPsiTime=PosPsiTime XBOUT.PsiList.append(PsiDefor.copy()) XBOUT.cputime.append( time.clock() - XBOUT.cputime[0] ) if SaveDict['SaveProgress']: iisave=np.arange(1,NumSteps.value,np.ceil(NumSteps.value/SaveDict['NumSavePoints'])) if any(iisave==iStep): PyLibs.io.save.h5file(SaveDict['OutputDir'], SaveDict['OutputFileRoot']+'.h5', *OutList) # END Time loop if SaveDict['Format'] != 'h5': write_SOL912_final(Time, PosPsiTime, NumNodes_tot, DynOut, Vrel, VrelDot, SaveDict) # Close output file if it exists. if 'writeDict' in kwords and Settings.WriteOut == True: fp.close() # Close TecPlot ASCII FileObject. if Settings.PlotTec==True: PostProcess.CloseAeroTecFile(FileObject) if XBOPTS.PrintInfo.value==True: sys.stdout.write(' ... done\n') # For interactive analysis at end of simulation set breakpoint. pass # sm I/O: FoR A velocities/accelerations XBOUT.Time=Time # ...dyn.dat XBOUT.PosPsiTime = PosPsiTime XBOUT.DynOut=DynOut # ...sgape.dat XBOUT.Vrel=Vrel # ...rigid.dat XBOUT.VrelDot=VrelDot XBOUT.PosPsiTime=PosPsiTime if SaveDict['SaveWake'] is True: #XBOUT.dirwake=dirwake XBOUT.NTwake=NumSteps.value//SaveDict['SaveWakeFreq'] #saveh5(SaveDict, AELAOPTS, VMINPUT, VMOPTS, XBOPTS, XBINPUT, XBOUT ) PyLibs.io.save.h5file(SaveDict['OutputDir'], SaveDict['OutputFileRoot']+'.h5', *OutList) return XBOUT
def Solve_Py(XBINPUT,XBOPTS,VMOPTS,VMINPUT,AELAOPTS,**kwords): """Nonlinear static solver using Python to solve aeroelastic equation. Assembly of structural matrices is carried out with Fortran subroutines. Aerodynamics solved using PyAero.UVLM.""" assert XBOPTS.Solution.value == 112, ('NonlinearStatic requested' + ' with wrong solution code') # I/O options XBOUT=DerivedTypes.Xboutput() SaveDict=Settings.SaveDict if 'SaveDict' in kwords: SaveDict=kwords['SaveDict'] if SaveDict['Format']=='h5': Settings.WriteOut=False Settings.PlotTec=False OutList=[AELAOPTS, VMINPUT, VMOPTS, XBOPTS, XBINPUT, XBOUT] #if VMINPUT.ctrlSurf!=None: # for cc in range(len(VMINPUT.ctrlSurf)): # OutList.append(VMINPUT.ctrlSurf[cc]) XBOUT.cputime.append(time.clock()) # time.processor_time more appropriate # Initialize beam. XBINPUT, XBOPTS, NumNodes_tot, XBELEM, PosIni, PsiIni, XBNODE, NumDof \ = BeamInit.Static(XBINPUT,XBOPTS) # Set initial conditions as undef config. PosDefor = PosIni.copy(order='F') PsiDefor = PsiIni.copy(order='F') if XBOPTS.PrintInfo.value==True: sys.stdout.write('Solve nonlinear static case in Python ... \n') # Initialise structural eqn tensors. KglobalFull = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F'); ks = ct.c_int() FglobalFull = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F'); fs = ct.c_int() DeltaS = np.zeros(NumDof.value, ct.c_double, 'F') Qglobal = np.zeros(NumDof.value, ct.c_double, 'F') x = np.zeros(NumDof.value, ct.c_double, 'F') dxdt = np.zeros(NumDof.value, ct.c_double, 'F') # Beam Load Step tensors Force = np.zeros((XBINPUT.NumNodesTot,6),ct.c_double,'F') ForceAero = np.zeros((XBINPUT.NumNodesTot,6),ct.c_double,'F') iForceStep = np.zeros((NumNodes_tot.value,6), ct.c_double, 'F') iForceStep_Dof = np.zeros(NumDof.value, ct.c_double, 'F') # Initialze Aero. Section = InitSection(VMOPTS,VMINPUT,AELAOPTS.ElasticAxis) # Declare memory for Aero grid and velocities. Zeta = np.zeros((Section.shape[0],PosDefor.shape[0],3),ct.c_double,'C') ZetaDot = np.zeros((Section.shape[0],PosDefor.shape[0],3),ct.c_double,'C') # Additional Aero solver variables. AeroForces = np.zeros((VMOPTS.M.value+1,VMOPTS.N.value+1,3),ct.c_double,'C') Gamma = np.zeros((VMOPTS.M.value,VMOPTS.N.value),ct.c_double,'C') # Init external velocities. Uext = InitSteadyExternalVels(VMOPTS,VMINPUT) # Create zero triads for motion of reference frame. VelA_A = np.zeros((3)) OmegaA_A = np.zeros((3)) # Create zero vectors for structural vars not used in static analysis. PosDotDef = np.zeros_like(PosDefor, ct.c_double, 'F') PsiDotDef = np.zeros_like(PsiDefor, ct.c_double, 'F') # Define tecplot stuff. FileName = Settings.OutputDir + Settings.OutputFileRoot + 'AeroGrid.dat' Variables = ['X', 'Y', 'Z','Gamma'] FileObject = PostProcess.WriteAeroTecHeader(FileName, 'Default', Variables) # Start Load Loop. for iLoadStep in range(XBOPTS.NumLoadSteps.value + XBOPTS.MaxIterations.value): # The loads are applied at increements. When # iLoadStep=XBOPTS.NumLoadSteps.value # further XBOPTS.MaxIterations.value iterations are run to the # aerodynamic loads to settle. # @warning: the number of for loops should be larger then # XBOPTS.NumLoadSteps.value, or full loading conditions will # not be reached # Reset convergence parameters and loads. Iter = 0 ResLog10 = 0.0 Force[:,:] = 0.0 AeroForces[:,:,:] = 0.0 oldPos = PosDefor.copy(order='F') oldPsi = PsiDefor.copy(order='F') # Calculate aero loads. if hasattr(XBINPUT, 'ForcedVel'): CoincidentGrid(PosDefor, PsiDefor, Section, XBINPUT.ForcedVel[0,:3], XBINPUT.ForcedVel[0,3:], PosDotDef, PsiDotDef, XBINPUT, Zeta, ZetaDot, np.zeros(3), XBINPUT.PsiA_G, # call from Couple_NlnFlightDyn ctrlSurf = VMINPUT.ctrlSurf) else: CoincidentGrid(PosDefor, PsiDefor, Section, VelA_A, OmegaA_A, PosDotDef, PsiDotDef, XBINPUT, Zeta, ZetaDot, np.zeros(3), XBINPUT.PsiA_G, # call from Couple_NlnFlightDyn ctrlSurf = VMINPUT.ctrlSurf) if hasattr(XBINPUT,'ForcedVel'): ZetaStar, GammaStar = InitSteadyWake(VMOPTS,VMINPUT,Zeta, XBINPUT.ForcedVel[0,:3]) else: ZetaStar, GammaStar = InitSteadyWake(VMOPTS,VMINPUT,Zeta) #>>>>>>>> HEAD # Solve for AeroForces. UVLMLib.Cpp_Solver_VLM(Zeta, ZetaDot, Uext, ZetaStar, VMOPTS, AeroForces, Gamma, GammaStar) # ======== # # Define AICs here for debgugging - Rob 16/08/2016 # 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') # # Solve for AeroForces. # UVLMLib.Cpp_Solver_VLM(Zeta, ZetaDot, Uext, ZetaStar, VMOPTS, # AeroForces, Gamma, GammaStar, AIC, BIC) # <<<<<<<< rob AeroForces[:,:,:] = AELAOPTS.AirDensity*AeroForces[:,:,:] # Write solution to tecplot file. if Settings.WriteOut==True and Settings.PlotTec==True: PostProcess.WriteUVLMtoTec(FileObject, Zeta, ZetaStar, Gamma, GammaStar, iLoadStep, XBOPTS.NumLoadSteps.value, iLoadStep*1.0, Text = True) # Map AeroForces to beam. CoincidentGridForce(XBINPUT, PsiDefor, Section, AeroForces, Force, PsiA_G=XBINPUT.PsiA_G) # Add gravity loads. # FoR A orientation is given by XBINPUT.PsiA_G AddGravityLoads(Force,XBINPUT,XBELEM,AELAOPTS, PsiDefor,VMINPUT.c, PsiA_G=XBINPUT.PsiA_G, FollowerForceRig=True) # Apply factor corresponding to force step. if iLoadStep < XBOPTS.NumLoadSteps.value: iForceStep = (Force + XBINPUT.ForceStatic)*float( (iLoadStep+1) )/\ XBOPTS.NumLoadSteps.value else: # continue at full loading until equilibrium iForceStep = Force + XBINPUT.ForceStatic if XBOPTS.PrintInfo.value == True: sys.stdout.write(' iLoad: %-10d\n' %(iLoadStep+1)) sys.stdout.write(' SubIter DeltaF DeltaX ResLog10\n') # Start Newton Iteration. while( (ResLog10 > np.log10(XBOPTS.MinDelta.value)) & (Iter < XBOPTS.MaxIterations.value) ): Iter += 1 if XBOPTS.PrintInfo.value == True: sys.stdout.write(' %-7d ' %(Iter)) # Set structural eqn tensors to zero KglobalFull[:,:] = 0.0; ks = ct.c_int() FglobalFull[:,:] = 0.0; fs = ct.c_int() Qglobal[:] = 0.0 # Assemble matrices for static problem BeamLib.Cbeam3_Asbly_Static(XBINPUT, NumNodes_tot, XBELEM, XBNODE, PosIni, PsiIni, PosDefor, PsiDefor, iForceStep, NumDof, ks, KglobalFull, fs, FglobalFull, Qglobal, XBOPTS) # Get state vector from current deformation. PosDot = np.zeros((NumNodes_tot.value,3), ct.c_double, 'F') PsiDot = np.zeros((XBINPUT.NumElems,Settings.MaxElNod,3), ct.c_double, 'F') BeamLib.Cbeam_Solv_Disp2State(NumNodes_tot, NumDof, XBINPUT, XBNODE, PosDefor, PsiDefor, PosDot, PsiDot, x, dxdt) # Get forces on unconstrained nodes. BeamLib.f_fem_m2v(ct.byref(NumNodes_tot), ct.byref(ct.c_int(6)), iForceStep.ctypes.data_as(ct.POINTER(ct.c_double)), ct.byref(NumDof), iForceStep_Dof.ctypes.data_as(ct.POINTER(ct.c_double)), XBNODE.Vdof.ctypes.data_as(ct.POINTER(ct.c_int)) ) # Calculate \Delta RHS. Qglobal = Qglobal - np.dot(FglobalFull, iForceStep_Dof) # Calculate \Delta State Vector. DeltaS = - np.dot(np.linalg.inv(KglobalFull), Qglobal) if XBOPTS.PrintInfo.value == True: sys.stdout.write('%-10.4e %-10.4e ' % (max(abs(Qglobal)),max(abs(DeltaS)))) # Update Solution. BeamLib.Cbeam3_Solv_Update_Static(XBINPUT, NumNodes_tot, XBELEM, XBNODE, NumDof, DeltaS, PosIni, PsiIni, PosDefor, PsiDefor) # Record residual at first iteration. if(Iter == 1): Res0_Qglobal = max(abs(Qglobal)) + 1.e-16 Res0_DeltaX = max(abs(DeltaS)) + 1.e-16 # Update residual and compute log10 Res_Qglobal = max(abs(Qglobal)) + 1.e-16 Res_DeltaX = max(abs(DeltaS)) + 1.e-16 ResLog10 = max([np.log10(Res_Qglobal/Res0_Qglobal), np.log10(Res_DeltaX/Res0_DeltaX)] ) if XBOPTS.PrintInfo.value == True: sys.stdout.write('%8.4f\n' %(ResLog10)) # Stop the solution. if(ResLog10 > 10.): sys.stderr.write(' STOP\n') sys.stderr.write(' The max residual is %e\n' %(ResLog10)) exit(1) elif Res_DeltaX < 1.e-14: break # END Newton iteration # Isolate Aerodynamic force CoincidentGridForce(XBINPUT, PsiDefor, Section, AeroForces, ForceAero, PsiA_G=XBINPUT.PsiA_G) # After incremental loading continue until equilibrium reached if iLoadStep >= XBOPTS.NumLoadSteps.value: Pos_error = PosDefor - oldPos Psi_error = PsiDefor - oldPsi if( (np.linalg.norm(Pos_error)<=XBOPTS.MinDelta) & \ (np.linalg.norm(Psi_error)<=XBOPTS.MinDelta) ): break # END Load step loop if XBOPTS.PrintInfo.value==True: sys.stdout.write(' ... done\n') if SaveDict['Format']!='h5': # Write deformed configuration to file. ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL112_def.dat' if XBOPTS.PrintInfo.value==True: sys.stdout.write('Writing file %s ... ' %(ofile)) fp = open(ofile,'w') fp.write('TITLE="Non-linear static solution: deformed geometry"\n') fp.write('VARIABLES="iElem" "iNode" "Px" "Py" "Pz" "Rx" "Ry" "Rz"\n') fp.close() if XBOPTS.PrintInfo.value==True: sys.stdout.write('done\n') WriteMode = 'a' # BeamIO.OutputElems(XBINPUT.NumElems, NumNodes_tot.value, XBELEM, PosDefor, PsiDefor, ofile, WriteMode) # Print deformed configuration. if XBOPTS.PrintInfo.value==True: sys.stdout.write('--------------------------------------\n') sys.stdout.write('NONLINEAR STATIC SOLUTION\n') sys.stdout.write('%10s %10s %10s\n' %('X','Y','Z')) for inodi in range(NumNodes_tot.value): sys.stdout.write(' ') for inodj in range(3): sys.stdout.write('%12.5e' %(PosDefor[inodi,inodj])) sys.stdout.write('\n') sys.stdout.write('--------------------------------------\n') # Close Tecplot ascii FileObject. PostProcess.CloseAeroTecFile(FileObject) # Drop output XBOUT.drop( PosIni=PosIni, PsiIni=PsiIni, PosDeforStatic=PosDefor, PsiDeforStatic=PsiDefor, ZetaStatic=Zeta, ZetaStarStatic=ZetaStar, GammaStatic=Gamma, GammaStarStatic=GammaStar, ForceStaticTotal=iForceStep, ForceAeroStatic=ForceAero, #iForceStepDebug=iForceStep, Uext=Uext ) PyLibs.io.save.h5file( SaveDict['OutputDir'], SaveDict['OutputFileRoot']+'.h5', *OutList) #>>>>>>> HEAD #======= if True: # print and save deformed wing total force coefficients (may include # gravity and other applied static loads). Coefficients in wind-axes. cF = np.zeros((3)) for i in range(VMOPTS.M.value+1): for j in range(VMOPTS.N.value+1): cF += AeroForces[i,j,:] Calpha=Psi2TransMat(np.array([VMINPUT.alpha, 0.0, 0.0])) cF=np.dot(Calpha,cF) cF=cF/( 0.5*AELAOPTS.AirDensity*np.linalg.norm(VMINPUT.U_infty)**2.0 \ *VMINPUT.c*XBINPUT.BeamLength) print("Reference condition total force coefficients: {}".format(cF)) fileName = Settings.OutputDir + Settings.OutputFileRoot + 'refCf' savemat(fileName,{'cF':cF}) #<<<<<<< rob # Return solution return XBOUT
def LoadAssembly(XBINPUT, XBELEM, XBNODE, XBOPTS, NumDof, \ PosIni, PsiIni, PosDefor, PsiDefor, \ Force_foll, Force_dead, CAG, iFactor): """@brief Assemble separate follower and dead loads. @param XBINPUT Xbeam inputs. @param XBELEM Xbeam element information. @param XBNODE Xbeam nodal information. @param XBOPTS Xbeam simulation options. @param NumDof numbers of DoF in the problem. @param PosInI nodal position at reference configuration. @param PsiIni nodal CRV at reference configuration. @param PosDefor nodal position at reference configuration. @param PsiDefor nodal CRV at reference configuration. @param Force_foll Matrix of applied nodal follower forces. @param Force_dead Matrix of applied nodal dead forces. @param CAG transformation matrix from inertial (G) to body-fixed frame (A). @param iFactor factor to account for optional load stepping. """ # Initialise function variables NumNodes_tot=ct.c_int((XBINPUT.NumNodesElem - 1)*XBINPUT.NumElems + 1) KglobalFull_foll = np.zeros((NumDof.value,NumDof.value),\ ct.c_double, 'F'); ksf = ct.c_int() FglobalFull_foll = np.zeros((NumDof.value,NumDof.value),\ ct.c_double, 'F'); fsf = ct.c_int() FglobalFull_dead = np.zeros((NumDof.value,NumDof.value),\ ct.c_double, 'F'); fsd = ct.c_int() Force_foll_Dof = np.zeros(NumDof.value, ct.c_double, 'F') Force_dead_Dof = np.zeros(NumDof.value, ct.c_double, 'F') # Assemble separate force coefficient matrices BeamLib.Cbeam3_Asbly_Fglobal(XBINPUT, NumNodes_tot, XBELEM, XBNODE,\ PosIni, PsiIni, PosDefor, PsiDefor,\ Force_foll*iFactor,NumDof,\ ksf, KglobalFull_foll, fsf, FglobalFull_foll,\ fsd, FglobalFull_dead, CAG) # Get follower and dead forces on constrained nodes BeamLib.f_fem_m2v(ct.byref(NumNodes_tot),\ ct.byref(ct.c_int(6)),\ Force_foll.ctypes.data_as(ct.POINTER(ct.c_double)),\ ct.byref(NumDof),\ Force_foll_Dof.ctypes.data_as(ct.POINTER(ct.c_double)),\ XBNODE.Vdof.ctypes.data_as(ct.POINTER(ct.c_int)) ) BeamLib.f_fem_m2v(ct.byref(NumNodes_tot),\ ct.byref(ct.c_int(6)),\ Force_dead.ctypes.data_as(ct.POINTER(ct.c_double)),\ ct.byref(NumDof),\ Force_dead_Dof.ctypes.data_as(ct.POINTER(ct.c_double)),\ XBNODE.Vdof.ctypes.data_as(ct.POINTER(ct.c_int)) ) # Project follower and dead forces Qforces = np.dot(FglobalFull_foll, Force_foll_Dof*iFactor) + np.dot(FglobalFull_dead, Force_dead_Dof*iFactor) #-------------------------------------- # Repeat in case of rigid-body dynamics if XBOPTS.Solution.value == 912: FrigidFull_foll = np.zeros((6,NumDof.value+6), ct.c_double, 'F'); frf = ct.c_int() FrigidFull_dead = np.zeros((6,NumDof.value+6), ct.c_double, 'F'); frd = ct.c_int() Force_foll_All = np.zeros(NumDof.value+6, ct.c_double, 'F') Force_dead_All = np.zeros(NumDof.value+6, ct.c_double, 'F') # Assemble separate force coefficient matrices BeamLib.Xbeam_Asbly_Frigid(XBINPUT, NumNodes_tot, XBELEM, XBNODE,\ PosIni, PsiIni, PosDefor, PsiDefor,\ NumDof, frf, FrigidFull_foll,\ frd, FrigidFull_dead, CAG) # Get follower and dead forces on unconstrained nodes BeamLib.f_fem_m2v_nofilter(ct.byref(NumNodes_tot),\ ct.byref(ct.c_int(6)),\ Force_foll.ctypes.data_as(ct.POINTER(ct.c_double)),\ ct.byref(ct.c_int(NumDof.value+6)),\ Force_foll_All.ctypes.data_as(ct.POINTER(ct.c_double)) ) BeamLib.f_fem_m2v_nofilter(ct.byref(NumNodes_tot),\ ct.byref(ct.c_int(6)),\ Force_dead.ctypes.data_as(ct.POINTER(ct.c_double)),\ ct.byref(ct.c_int(NumDof.value+6)),\ Force_dead_All.ctypes.data_as(ct.POINTER(ct.c_double)) ) # Project follower and dead forces Qrigid = np.dot(FrigidFull_foll,Force_foll_All*iFactor) + np.dot(FrigidFull_dead,Force_dead_All*iFactor) else: Qrigid = 0.0 #------------------ # Return everything return Qforces, KglobalFull_foll, Qrigid
def Solve_Py(XBINPUT, XBOPTS, moduleName=None): """Nonlinear dynamic structural solver in Python. Assembly of matrices is carried out with Fortran subroutines.""" "Check correct solution code" assert XBOPTS.Solution.value == 312, ('NonlinearDynamic requested' +\ ' with wrong solution code') "Initialise beam" XBINPUT, XBOPTS, NumNodes_tot, XBELEM, PosIni, PsiIni, XBNODE, NumDof \ = BeamInit.Static(XBINPUT,XBOPTS, moduleName) # Solve static solution XBOPTS.Solution.value = 112 PosDefor, PsiDefor = Solve_Py_Static(XBINPUT, XBOPTS, moduleName) XBOPTS.Solution.value = 312 "Write deformed configuration to file" ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL312_def.dat' if XBOPTS.PrintInfo == True: sys.stdout.write('Writing file %s ... ' % (ofile)) fp = open(ofile, 'w') fp.write('TITLE="Non-linear static solution: deformed geometry"\n') fp.write('VARIABLES="iElem" "iNode" "Px" "Py" "Pz" "Rx" "Ry" "Rz"\n') fp.close() if XBOPTS.PrintInfo == True: sys.stdout.write('done\n') WriteMode = 'a' BeamIO.OutputElems(XBINPUT.NumElems, NumNodes_tot.value, XBELEM, \ PosDefor, PsiDefor, ofile, WriteMode) "Initialise variables for dynamic analysis" Time, NumSteps, ForceTime, ForcedVel, ForcedVelDot,\ PosDotDef, PsiDotDef,\ OutGrids, PosPsiTime, VelocTime, DynOut\ = BeamInit.Dynamic(XBINPUT,XBOPTS, moduleName) # Delete unused vars del OutGrids, VelocTime "Write _force file" ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL312_force.dat' fp = open(ofile, 'w') BeamIO.Write_force_File(fp, Time, ForceTime, ForcedVel, ForcedVelDot) fp.close() "Write _vel file" #TODO: write _vel file "Write .mrb file" #TODO: write .mrb file if XBOPTS.PrintInfo.value == True: sys.stdout.write('Solve nonlinear dynamic case in Python ... \n') "Initialise structural system tensors" MglobalFull = np.zeros((NumDof.value, NumDof.value), ct.c_double, 'F') CglobalFull = np.zeros((NumDof.value, NumDof.value), ct.c_double, 'F') KglobalFull = np.zeros((NumDof.value, NumDof.value), ct.c_double, 'F') FglobalFull = np.zeros((NumDof.value, NumDof.value), ct.c_double, 'F') Asys = np.zeros((NumDof.value, NumDof.value), ct.c_double, 'F') ms = ct.c_int() cs = ct.c_int() ks = ct.c_int() fs = ct.c_int() Mvel = np.zeros((NumDof.value, 6), ct.c_double, 'F') Cvel = np.zeros((NumDof.value, 6), ct.c_double, 'F') X = np.zeros(NumDof.value, ct.c_double, 'F') DX = np.zeros(NumDof.value, ct.c_double, 'F') dXdt = np.zeros(NumDof.value, ct.c_double, 'F') dXddt = np.zeros(NumDof.value, ct.c_double, 'F') Force_Dof = np.zeros(NumDof.value, ct.c_double, 'F') Qglobal = np.zeros(NumDof.value, ct.c_double, 'F') "Initialise rotation operators" Unit = np.zeros((3, 3), ct.c_double, 'F') for i in range(3): Unit[i, i] = 1.0 Unit4 = np.zeros((4, 4), ct.c_double, 'F') for i in range(4): Unit4[i, i] = 1.0 Cao = Unit.copy('F') Temp = Unit4.copy('F') Quat = np.zeros(4, ct.c_double, 'F') Quat[0] = 1.0 "Extract initial displacements and velocities" BeamLib.Cbeam_Solv_Disp2State(NumNodes_tot, NumDof, XBINPUT, XBNODE,\ PosDefor, PsiDefor, PosDotDef, PsiDotDef, X, dXdt) "Approximate initial accelerations" "Initialise accelerations as zero arrays" PosDotDotDef = np.zeros((NumNodes_tot.value, 3), ct.c_double, 'F') PsiDotDotDef = np.zeros((XBINPUT.NumElems,Settings.MaxElNod,3),\ ct.c_double, 'F') "Force at the first time-step" Force = (XBINPUT.ForceStatic + XBINPUT.ForceDyn * ForceTime[0]).copy('F') "Assemble matrices for dynamic analysis" BeamLib.Cbeam3_Asbly_Dynamic(XBINPUT, NumNodes_tot, XBELEM, XBNODE,\ PosIni, PsiIni, PosDefor, PsiDefor,\ PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef,\ Force, ForcedVel[0,:], ForcedVelDot[0,:],\ NumDof, Settings.DimMat,\ ms, MglobalFull, Mvel,\ cs, CglobalFull, Cvel,\ ks, KglobalFull, fs, FglobalFull,\ Qglobal, XBOPTS, Cao) "Get force vector for unconstrained nodes (Force_Dof)" BeamLib.f_fem_m2v(ct.byref(NumNodes_tot),\ ct.byref(ct.c_int(6)),\ Force.ctypes.data_as(ct.POINTER(ct.c_double)),\ ct.byref(NumDof),\ Force_Dof.ctypes.data_as(ct.POINTER(ct.c_double)),\ XBNODE.Vdof.ctypes.data_as(ct.POINTER(ct.c_int)) ) "Get RHS at initial condition" Qglobal += -np.dot(FglobalFull, Force_Dof) #Separate assembly of follower and dead loads" tmpForceTime = ForceTime[0].copy('F') Qforces = XbeamLib.LoadAssembly(XBINPUT, XBELEM, XBNODE, XBOPTS, NumDof, \ PosIni, PsiIni, PosDefor, PsiDefor, \ (XBINPUT.ForceStatic_foll + XBINPUT.ForceDyn_foll*tmpForceTime), \ (XBINPUT.ForceStatic_dead + XBINPUT.ForceDyn_dead*tmpForceTime), \ Cao, 1)[0] Qglobal -= Qforces "Initial Accel" dXddt[:] = np.dot(np.linalg.inv(MglobalFull), -Qglobal) "Record position of all grid points in global FoR at initial time step" DynOut[0:NumNodes_tot.value, :] = PosDefor "Position/rotation of the selected node in initial deformed configuration" PosPsiTime[0, :3] = PosDefor[-1, :] PosPsiTime[0, 3:] = PsiDefor[-1, XBELEM.NumNodes[-1] - 1, :] "Get gamma and beta for Newmark scheme" gamma = 0.5 + XBOPTS.NewmarkDamp.value beta = 0.25 * np.power((gamma + 0.5), 2.0) "Time loop" for iStep in range(NumSteps.value): if XBOPTS.PrintInfo.value == True: sys.stdout.write(' Time: %-10.4e\n' % (Time[iStep + 1])) sys.stdout.write(' SubIter DeltaF DeltaX ResLog10\n') "calculate dt" dt = Time[iStep + 1] - Time[iStep] "Update transformation matrix for given angular velocity" Temp = np.linalg.inv(Unit4 + 0.25 * XbeamLib.QuadSkew(ForcedVel[iStep + 1, 3:]) * dt) Quat = np.dot( Temp, np.dot(Unit4 - 0.25 * XbeamLib.QuadSkew(ForcedVel[iStep, 3:]) * dt, Quat)) Quat = Quat / np.linalg.norm(Quat) Cao = XbeamLib.Rot(Quat) "Predictor step" X += dt * dXdt + (0.5 - beta) * dXddt * dt**2 dXdt += (1.0 - gamma) * dXddt * dt dXddt[:] = 0.0 "Force at current time-step" Force = (XBINPUT.ForceStatic + \ XBINPUT.ForceDyn*ForceTime[iStep+1]).copy('F') "Reset convergence parameters" Iter = 0 ResLog10 = 1.0 "Newton-Raphson loop" while ( (ResLog10 > XBOPTS.MinDelta.value) \ & (Iter < XBOPTS.MaxIterations.value) ): "set tensors to zero" Qglobal[:] = 0.0 Mvel[:, :] = 0.0 Cvel[:, :] = 0.0 MglobalFull[:, :] = 0.0 CglobalFull[:, :] = 0.0 KglobalFull[:, :] = 0.0 FglobalFull[:, :] = 0.0 "Update counter" Iter += 1 if XBOPTS.PrintInfo.value == True: sys.stdout.write(' %-7d ' % (Iter)) "nodal diplacements and velocities from state vector" BeamLib.Cbeam3_Solv_State2Disp(XBINPUT, NumNodes_tot, XBELEM, XBNODE, PosIni, PsiIni, NumDof, X, dXdt,\ PosDefor, PsiDefor, PosDotDef, PsiDotDef) "update matrices" BeamLib.Cbeam3_Asbly_Dynamic(XBINPUT, NumNodes_tot, XBELEM, XBNODE,\ PosIni, PsiIni, PosDefor, PsiDefor,\ PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef,\ Force, ForcedVel[iStep+1,:], ForcedVelDot[iStep+1,:],\ NumDof, Settings.DimMat,\ ms, MglobalFull, Mvel,\ cs, CglobalFull, Cvel,\ ks, KglobalFull, fs, FglobalFull,\ Qglobal, XBOPTS, Cao) "Get force vector for unconstrained nodes (Force_Dof)" BeamLib.f_fem_m2v(ct.byref(NumNodes_tot),\ ct.byref(ct.c_int(6)),\ Force.ctypes.data_as(ct.POINTER(ct.c_double)),\ ct.byref(NumDof),\ Force_Dof.ctypes.data_as(ct.POINTER(ct.c_double)),\ XBNODE.Vdof.ctypes.data_as(ct.POINTER(ct.c_int)) ) "Solve for update vector" "Residual" Qglobal += np.dot(MglobalFull, dXddt) \ + np.dot(Mvel,ForcedVelDot[iStep+1,:]) \ - np.dot(FglobalFull, Force_Dof) #Separate assembly of follower and dead loads tmpForceTime = ForceTime[iStep + 1].copy('F') Qforces = XbeamLib.LoadAssembly(XBINPUT, XBELEM, XBNODE, XBOPTS, NumDof, \ PosIni, PsiIni, PosDefor, PsiDefor, \ (XBINPUT.ForceStatic_foll + XBINPUT.ForceDyn_foll*tmpForceTime), \ (XBINPUT.ForceStatic_dead + XBINPUT.ForceDyn_dead*tmpForceTime), \ Cao,1)[0] Qglobal -= Qforces if XBOPTS.PrintInfo.value == True: sys.stdout.write('%-10.4e ' % (max(abs(Qglobal)))) "Calculate system matrix for update calculation" Asys = KglobalFull + \ CglobalFull*gamma/(beta*dt) + \ MglobalFull/(beta*np.power(dt,2.0)) "Solve for update" DX[:] = np.dot(np.linalg.inv(Asys), -Qglobal) "Corrector step" X += DX dXdt += DX * gamma / (beta * dt) dXddt += DX / (beta * dt**2) "Residual at first iteration" if (Iter == 1): Res0_Qglobal = max(max(abs(Qglobal)), 1) Res0_DeltaX = max(max(abs(DX)), 1) "Update residual and compute log10" Res_Qglobal = max(abs(Qglobal)) Res_DeltaX = max(abs(DX)) ResLog10 = max(Res_Qglobal / Res0_Qglobal, Res_DeltaX / Res0_DeltaX) if XBOPTS.PrintInfo.value == True: sys.stdout.write('%-10.4e %8.4f\n' % (max(abs(DX)), ResLog10)) "END Netwon-Raphson" "update to converged nodal displacements and velocities" BeamLib.Cbeam3_Solv_State2Disp(XBINPUT, NumNodes_tot, XBELEM, XBNODE, PosIni, PsiIni, NumDof, X, dXdt, PosDefor, PsiDefor, PosDotDef, PsiDotDef) PosPsiTime[iStep + 1, :3] = PosDefor[(NumNodes_tot.value - 1) / 2 + 1, :] PosPsiTime[iStep + 1, 3:] = PsiDefor[-1, XBELEM.NumNodes[-1] - 1, :] "Position of all grid points in global FoR" i1 = (iStep + 1) * NumNodes_tot.value i2 = (iStep + 2) * NumNodes_tot.value DynOut[i1:i2, :] = PosDefor "END Time loop" "Write _dyn file" ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL312_dyn.dat' fp = open(ofile, 'w') BeamIO.Write_dyn_File(fp, Time, PosPsiTime) fp.close() "Write _shape file" ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL312_shape.dat' fp = open(ofile, 'w') BeamIO.Write_shape_File(fp, len(Time), NumNodes_tot.value, Time, DynOut) fp.close() if XBOPTS.PrintInfo.value == True: sys.stdout.write(' ... done\n')
def LoadAssembly(XBINPUT, XBELEM, XBNODE, XBOPTS, NumDof, \ PosIni, PsiIni, PosDefor, PsiDefor, \ Force_foll, Force_dead, CAG, iFactor): """@brief Assemble separate follower and dead loads. @param XBINPUT Xbeam inputs. @param XBELEM Xbeam element information. @param XBNODE Xbeam nodal information. @param XBOPTS Xbeam simulation options. @param NumDof numbers of DoF in the problem. @param PosInI nodal position at reference configuration. @param PsiIni nodal CRV at reference configuration. @param PosDefor nodal position at reference configuration. @param PsiDefor nodal CRV at reference configuration. @param Force_foll Matrix of applied nodal follower forces. @param Force_dead Matrix of applied nodal dead forces. @param CAG transformation matrix from inertial (G) to body-fixed frame (A). @param iFactor factor to account for optional load stepping. """ # Initialise function variables NumNodes_tot = ct.c_int((XBINPUT.NumNodesElem - 1) * XBINPUT.NumElems + 1) KglobalFull_foll = np.zeros((NumDof.value,NumDof.value),\ ct.c_double, 'F') ksf = ct.c_int() FglobalFull_foll = np.zeros((NumDof.value,NumDof.value),\ ct.c_double, 'F') fsf = ct.c_int() FglobalFull_dead = np.zeros((NumDof.value,NumDof.value),\ ct.c_double, 'F') fsd = ct.c_int() Force_foll_Dof = np.zeros(NumDof.value, ct.c_double, 'F') Force_dead_Dof = np.zeros(NumDof.value, ct.c_double, 'F') # Assemble separate force coefficient matrices BeamLib.Cbeam3_Asbly_Fglobal(XBINPUT, NumNodes_tot, XBELEM, XBNODE,\ PosIni, PsiIni, PosDefor, PsiDefor,\ Force_foll*iFactor,NumDof,\ ksf, KglobalFull_foll, fsf, FglobalFull_foll,\ fsd, FglobalFull_dead, CAG) # Get follower and dead forces on constrained nodes BeamLib.f_fem_m2v(ct.byref(NumNodes_tot),\ ct.byref(ct.c_int(6)),\ Force_foll.ctypes.data_as(ct.POINTER(ct.c_double)),\ ct.byref(NumDof),\ Force_foll_Dof.ctypes.data_as(ct.POINTER(ct.c_double)),\ XBNODE.Vdof.ctypes.data_as(ct.POINTER(ct.c_int)) ) BeamLib.f_fem_m2v(ct.byref(NumNodes_tot),\ ct.byref(ct.c_int(6)),\ Force_dead.ctypes.data_as(ct.POINTER(ct.c_double)),\ ct.byref(NumDof),\ Force_dead_Dof.ctypes.data_as(ct.POINTER(ct.c_double)),\ XBNODE.Vdof.ctypes.data_as(ct.POINTER(ct.c_int)) ) # Project follower and dead forces Qforces = np.dot(FglobalFull_foll, Force_foll_Dof * iFactor) + np.dot( FglobalFull_dead, Force_dead_Dof * iFactor) #-------------------------------------- # Repeat in case of rigid-body dynamics if XBOPTS.Solution.value == 912: FrigidFull_foll = np.zeros((6, NumDof.value + 6), ct.c_double, 'F') frf = ct.c_int() FrigidFull_dead = np.zeros((6, NumDof.value + 6), ct.c_double, 'F') frd = ct.c_int() Force_foll_All = np.zeros(NumDof.value + 6, ct.c_double, 'F') Force_dead_All = np.zeros(NumDof.value + 6, ct.c_double, 'F') # Assemble separate force coefficient matrices BeamLib.Xbeam_Asbly_Frigid(XBINPUT, NumNodes_tot, XBELEM, XBNODE,\ PosIni, PsiIni, PosDefor, PsiDefor,\ NumDof, frf, FrigidFull_foll,\ frd, FrigidFull_dead, CAG) # Get follower and dead forces on unconstrained nodes BeamLib.f_fem_m2v_nofilter(ct.byref(NumNodes_tot),\ ct.byref(ct.c_int(6)),\ Force_foll.ctypes.data_as(ct.POINTER(ct.c_double)),\ ct.byref(ct.c_int(NumDof.value+6)),\ Force_foll_All.ctypes.data_as(ct.POINTER(ct.c_double)) ) BeamLib.f_fem_m2v_nofilter(ct.byref(NumNodes_tot),\ ct.byref(ct.c_int(6)),\ Force_dead.ctypes.data_as(ct.POINTER(ct.c_double)),\ ct.byref(ct.c_int(NumDof.value+6)),\ Force_dead_All.ctypes.data_as(ct.POINTER(ct.c_double)) ) # Project follower and dead forces Qrigid = np.dot(FrigidFull_foll, Force_foll_All * iFactor) + np.dot( FrigidFull_dead, Force_dead_All * iFactor) else: Qrigid = 0.0 #------------------ # Return everything return Qforces, KglobalFull_foll, Qrigid
def Solve_Py(XBINPUT, XBOPTS): """Nonlinear dynamic structural solver in Python. Assembly of matrices is carried out with Fortran subroutines.""" #Check correct solution code assert XBOPTS.Solution.value == 912, ('NonlinearDynamic requested' +\ ' with wrong solution code') #Initialise beam XBINPUT, XBOPTS, NumNodes_tot, XBELEM, PosIni, PsiIni, XBNODE, NumDof \ = BeamInit.Static(XBINPUT,XBOPTS) #Solve static XBOPTS.Solution.value = 112 PosDefor, PsiDefor = Solve_Py_Static(XBINPUT, XBOPTS) XBOPTS.Solution.value = 912 #Write deformed configuration to file ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL912_def.dat' if XBOPTS.PrintInfo == True: sys.stdout.write('Writing file %s ... ' % (ofile)) fp = open(ofile, 'w') fp.write('TITLE="Non-linear static solution: deformed geometry"\n') fp.write('VARIABLES="iElem" "iNode" "Px" "Py" "Pz" "Rx" "Ry" "Rz"\n') fp.close() if XBOPTS.PrintInfo == True: sys.stdout.write('done\n') WriteMode = 'a' BeamIO.OutputElems(XBINPUT.NumElems, NumNodes_tot.value, XBELEM, \ PosDefor, PsiDefor, ofile, WriteMode) #Initialise variables for dynamic analysis Time, NumSteps, ForceTime, Vrel, VrelDot,\ PosDotDef, PsiDotDef,\ OutGrids, PosPsiTime, VelocTime, DynOut\ = BeamInit.Dynamic(XBINPUT,XBOPTS) # Delete unused variables. del OutGrids, VelocTime #Write _force file ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL912_force.dat' fp = open(ofile, 'w') BeamIO.Write_force_File(fp, Time, ForceTime, Vrel, VrelDot) fp.close() if XBOPTS.PrintInfo.value == True: sys.stdout.write('Solve nonlinear dynamic case in Python ... \n') #Initialise structural system tensors MssFull = np.zeros((NumDof.value, NumDof.value), ct.c_double, 'F') CssFull = np.zeros((NumDof.value, NumDof.value), ct.c_double, 'F') KssFull = np.zeros((NumDof.value, NumDof.value), ct.c_double, 'F') FstrucFull = np.zeros((NumDof.value, NumDof.value), ct.c_double, 'F') ms = ct.c_int() cs = ct.c_int() ks = ct.c_int() fs = ct.c_int() Msr = np.zeros((NumDof.value, 6), ct.c_double, 'F') Csr = np.zeros((NumDof.value, 6), ct.c_double, 'F') X = np.zeros(NumDof.value, ct.c_double, 'F') dXdt = np.zeros(NumDof.value, ct.c_double, 'F') Force_Dof = np.zeros(NumDof.value, ct.c_double, 'F') Qstruc = np.zeros(NumDof.value, ct.c_double, 'F') #Initialise rigid-body system tensors MrsFull = np.zeros((6, NumDof.value), ct.c_double, 'F') CrsFull = np.zeros((6, NumDof.value), ct.c_double, 'F') KrsFull = np.zeros((6, NumDof.value), ct.c_double, 'F') FrigidFull = np.zeros((6, NumDof.value + 6), ct.c_double, 'F') mr = ct.c_int() cr = ct.c_int() kr = ct.c_int() fr = ct.c_int() Mrr = np.zeros((6, 6), ct.c_double, 'F') Crr = np.zeros((6, 6), ct.c_double, 'F') Qrigid = np.zeros(6, ct.c_double, 'F') #Initialise full system tensors Q = np.zeros(NumDof.value + 6 + 4, ct.c_double, 'F') DQ = np.zeros(NumDof.value + 6 + 4, ct.c_double, 'F') dQdt = np.zeros(NumDof.value + 6 + 4, ct.c_double, 'F') dQddt = np.zeros(NumDof.value + 6 + 4, ct.c_double, 'F') Force_All = np.zeros(NumDof.value + 6, ct.c_double, 'F') Msys = np.zeros((NumDof.value + 6 + 4, NumDof.value + 6 + 4), ct.c_double, 'F') Csys = np.zeros((NumDof.value + 6 + 4, NumDof.value + 6 + 4), ct.c_double, 'F') Ksys = np.zeros((NumDof.value + 6 + 4, NumDof.value + 6 + 4), ct.c_double, 'F') Asys = np.zeros((NumDof.value + 6 + 4, NumDof.value + 6 + 4), ct.c_double, 'F') Qsys = np.zeros(NumDof.value + 6 + 4, ct.c_double, 'F') #Initialise rotation operators Quat = np.zeros(4, ct.c_double, 'F') Quat[0] = 1.0 Cao = XbeamLib.Rot(Quat) ACoa = np.zeros((6, 6), ct.c_double, 'F') Cqr = np.zeros((4, 6), ct.c_double, 'F') Cqq = np.zeros((4, 4), ct.c_double, 'F') Unit4 = np.zeros((4, 4), ct.c_double, 'F') for i in range(4): Unit4[i, i] = 1.0 #Extract initial displacements and velocities BeamLib.Cbeam_Solv_Disp2State(NumNodes_tot, NumDof, XBINPUT, XBNODE,\ PosDefor, PsiDefor, PosDotDef, PsiDotDef, X, dXdt) #Initialise accelerations as zero arrays PosDotDotDef = np.zeros((NumNodes_tot.value, 3), ct.c_double, 'F') PsiDotDotDef = np.zeros((XBINPUT.NumElems,Settings.MaxElNod,3),\ ct.c_double, 'F') #Populate state vector Q[:NumDof.value] = X.copy('F') dQdt[:NumDof.value] = dXdt.copy('F') dQdt[NumDof.value:NumDof.value + 6] = Vrel[0, :].copy('F') dQdt[NumDof.value + 6:] = Quat.copy('F') #Force at the first time-step Force = (XBINPUT.ForceStatic + XBINPUT.ForceDyn * ForceTime[0]).copy('F') #Assemble matrices and loads for structural dynamic analysis tmpVrel = Vrel[0, :].copy('F') tmpQuat = Quat.copy('F') BeamLib.Cbeam3_Asbly_Dynamic(XBINPUT, NumNodes_tot, XBELEM, XBNODE,\ PosIni, PsiIni, PosDefor, PsiDefor,\ PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef,\ Force, tmpVrel, 0*tmpVrel,\ NumDof, Settings.DimMat,\ ms, MssFull, Msr,\ cs, CssFull, Csr,\ ks, KssFull, fs, FstrucFull,\ Qstruc, XBOPTS, Cao) BeamLib.f_fem_m2v(ct.byref(NumNodes_tot),\ ct.byref(ct.c_int(6)),\ Force.ctypes.data_as(ct.POINTER(ct.c_double)),\ ct.byref(NumDof),\ Force_Dof.ctypes.data_as(ct.POINTER(ct.c_double)),\ XBNODE.Vdof.ctypes.data_as(ct.POINTER(ct.c_int)) ) Qstruc -= np.dot(FstrucFull, Force_Dof) #Assemble matrices for rigid-body dynamic analysis BeamLib.Xbeam_Asbly_Dynamic(XBINPUT, NumNodes_tot, XBELEM, XBNODE,\ PosIni, PsiIni, PosDefor, PsiDefor,\ PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef,\ tmpVrel, 0*tmpVrel, tmpQuat,\ NumDof, Settings.DimMat,\ mr, MrsFull, Mrr,\ cr, CrsFull, Crr, Cqr, Cqq,\ kr, KrsFull, fr, FrigidFull,\ Qrigid, XBOPTS, Cao) BeamLib.f_fem_m2v_nofilter(ct.byref(NumNodes_tot),\ ct.byref(ct.c_int(6)),\ Force.ctypes.data_as(ct.POINTER(ct.c_double)),\ ct.byref(ct.c_int(NumDof.value+6)),\ Force_All.ctypes.data_as(ct.POINTER(ct.c_double)) ) Qrigid -= np.dot(FrigidFull, Force_All) #Separate assembly of follower and dead loads tmpForceTime = ForceTime[0].copy('F') tmpQforces,Dummy,tmpQrigid = XbeamLib.LoadAssembly(XBINPUT, XBELEM, XBNODE, XBOPTS, NumDof, \ PosIni, PsiIni, PosDefor, PsiDefor, \ (XBINPUT.ForceStatic_foll + XBINPUT.ForceDyn_foll*tmpForceTime), \ (XBINPUT.ForceStatic_dead + XBINPUT.ForceDyn_dead*tmpForceTime), \ Cao,1) Qstruc -= tmpQforces Qrigid -= tmpQrigid #Assemble system matrices Msys[:NumDof.value, :NumDof.value] = MssFull.copy('F') Msys[:NumDof.value, NumDof.value:NumDof.value + 6] = Msr.copy('F') Msys[NumDof.value:NumDof.value + 6, :NumDof.value] = MrsFull.copy('F') Msys[NumDof.value:NumDof.value + 6, NumDof.value:NumDof.value + 6] = Mrr.copy('F') Msys[NumDof.value + 6:, NumDof.value + 6:] = Unit4.copy('F') Qsys[:NumDof.value] = Qstruc Qsys[NumDof.value:NumDof.value + 6] = Qrigid Qsys[NumDof.value + 6:] = np.dot(Cqq, dQdt[NumDof.value + 6:]) #Initial Accel dQddt[:] = np.dot(np.linalg.inv(Msys), -Qsys) #Record position of all grid points in global FoR at initial time step DynOut[0:NumNodes_tot.value, :] = PosDefor #Position/rotation of the selected node in initial deformed configuration PosPsiTime[0, :3] = PosDefor[-1, :] PosPsiTime[0, 3:] = PsiDefor[-1, XBELEM.NumNodes[-1] - 1, :] #Get gamma and beta for Newmark scheme gamma = 0.5 + XBOPTS.NewmarkDamp.value beta = 0.25 * (gamma + 0.5)**2 #Time loop for iStep in range(NumSteps.value): if XBOPTS.PrintInfo.value == True: sys.stdout.write(' Time: %-10.4e\n' % (Time[iStep + 1])) sys.stdout.write(' SubIter DeltaF DeltaX ResLog10\n') #calculate dt dt = Time[iStep + 1] - Time[iStep] #Predictor step Q += dt * dQdt + (0.5 - beta) * dQddt * dt**2 dQdt += (1.0 - gamma) * dQddt * dt dQddt[:] = 0.0 #Force at current time-step Force = (XBINPUT.ForceStatic + \ XBINPUT.ForceDyn*ForceTime[iStep+1]).copy('F') #Reset convergence parameters Iter = 0 ResLog10 = 1.0 #Newton-Raphson loop while ( (ResLog10 > XBOPTS.MinDelta.value) \ & (Iter < XBOPTS.MaxIterations.value) ): #set tensors to zero MssFull[:, :] = 0.0 CssFull[:, :] = 0.0 KssFull[:, :] = 0.0 FstrucFull[:, :] = 0.0 Msr[:, :] = 0.0 Csr[:, :] = 0.0 Qstruc[:] = 0.0 MrsFull[:, :] = 0.0 CrsFull[:, :] = 0.0 KrsFull[:, :] = 0.0 FrigidFull[:, :] = 0.0 Mrr[:, :] = 0.0 Crr[:, :] = 0.0 Qrigid[:] = 0.0 Msys[:, :] = 0.0 Csys[:, :] = 0.0 Ksys[:, :] = 0.0 Asys[:, :] = 0.0 Qsys[:] = 0.0 #Update counter Iter += 1 if XBOPTS.PrintInfo.value == True: sys.stdout.write(' %-7d ' % (Iter)) #nodal diplacements and velocities from state vector X = Q[:NumDof.value].copy('F') dXdt = dQdt[:NumDof.value].copy('F') BeamLib.Cbeam3_Solv_State2Disp(XBINPUT, NumNodes_tot, XBELEM, XBNODE, PosIni, PsiIni, NumDof, X, dXdt,\ PosDefor, PsiDefor, PosDotDef, PsiDotDef) #rigid-body velocities and orientation from state vector Vrel[iStep + 1, :] = dQdt[NumDof.value:NumDof.value + 6].copy('F') VrelDot[iStep + 1, :] = dQddt[NumDof.value:NumDof.value + 6].copy('F') Quat = dQdt[NumDof.value + 6:].copy('F') Quat = Quat / np.linalg.norm(Quat) Cao = XbeamLib.Rot(Quat) #Assemble matrices and loads for structural dynamic analysis tmpVrel = Vrel[iStep + 1, :].copy('F') tmpQuat = Quat.copy('F') BeamLib.Cbeam3_Asbly_Dynamic(XBINPUT, NumNodes_tot, XBELEM, XBNODE,\ PosIni, PsiIni, PosDefor, PsiDefor,\ PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef,\ Force, tmpVrel, 0*tmpVrel,\ NumDof, Settings.DimMat,\ ms, MssFull, Msr,\ cs, CssFull, Csr,\ ks, KssFull, fs, FstrucFull,\ Qstruc, XBOPTS, Cao) BeamLib.f_fem_m2v(ct.byref(NumNodes_tot),\ ct.byref(ct.c_int(6)),\ Force.ctypes.data_as(ct.POINTER(ct.c_double)),\ ct.byref(NumDof),\ Force_Dof.ctypes.data_as(ct.POINTER(ct.c_double)),\ XBNODE.Vdof.ctypes.data_as(ct.POINTER(ct.c_int)) ) #Assemble matrices for rigid-body dynamic analysis BeamLib.Xbeam_Asbly_Dynamic(XBINPUT, NumNodes_tot, XBELEM, XBNODE,\ PosIni, PsiIni, PosDefor, PsiDefor,\ PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef,\ tmpVrel, 0*tmpVrel, tmpQuat,\ NumDof, Settings.DimMat,\ mr, MrsFull, Mrr,\ cr, CrsFull, Crr, Cqr, Cqq,\ kr, KrsFull, fs, FrigidFull,\ Qrigid, XBOPTS, Cao) BeamLib.f_fem_m2v_nofilter(ct.byref(NumNodes_tot),\ ct.byref(ct.c_int(6)),\ Force.ctypes.data_as(ct.POINTER(ct.c_double)),\ ct.byref(ct.c_int(NumDof.value+6)),\ Force_All.ctypes.data_as(ct.POINTER(ct.c_double)) ) #Residual at first iteration if (Iter == 1): Res0_Qglobal = max(max(abs(Qsys)), 1) Res0_DeltaX = max(max(abs(DQ)), 1) #Assemble discrete system matrices with linearised quaternion equations Msys[:NumDof.value, :NumDof.value] = MssFull.copy('F') Msys[:NumDof.value, NumDof.value:NumDof.value + 6] = Msr.copy('F') Msys[NumDof.value:NumDof.value + 6, :NumDof.value] = MrsFull.copy('F') Msys[NumDof.value:NumDof.value + 6, NumDof.value:NumDof.value + 6] = Mrr.copy('F') Msys[NumDof.value + 6:, NumDof.value + 6:] = Unit4.copy('F') Csys[:NumDof.value, :NumDof.value] = CssFull.copy('F') Csys[:NumDof.value, NumDof.value:NumDof.value + 6] = Csr.copy('F') Csys[NumDof.value:NumDof.value + 6, :NumDof.value] = CrsFull.copy('F') Csys[NumDof.value:NumDof.value + 6, NumDof.value:NumDof.value + 6] = Crr.copy('F') Csys[NumDof.value + 6:, NumDof.value:NumDof.value + 6] = Cqr.copy('F') Csys[NumDof.value + 6:, NumDof.value + 6:] = Cqq.copy('F') Ksys[:NumDof.value, :NumDof.value] = KssFull.copy('F') Ksys[NumDof.value:NumDof.value + 6, :NumDof.value] = KrsFull.copy('F') #Separate assembly of follower and dead loads tmpForceTime = ForceTime[iStep + 1].copy('F') tmpQforces,Dummy,tmpQrigid = XbeamLib.LoadAssembly(XBINPUT, XBELEM, XBNODE, XBOPTS, NumDof, \ PosIni, PsiIni, PosDefor, PsiDefor, \ (XBINPUT.ForceStatic_foll + XBINPUT.ForceDyn_foll*tmpForceTime), \ (XBINPUT.ForceStatic_dead + XBINPUT.ForceDyn_dead*tmpForceTime), \ Cao,1) Qstruc -= tmpQforces Qrigid -= tmpQrigid #Compute residual Qstruc += -np.dot(FstrucFull, Force_Dof) Qrigid += -np.dot(FrigidFull, Force_All) Qsys[:NumDof.value] = Qstruc Qsys[NumDof.value:NumDof.value + 6] = Qrigid Qsys[NumDof.value + 6:] = np.dot(Cqq, dQdt[NumDof.value + 6:]) Qsys += np.dot(Msys, dQddt) #Calculate system matrix for update calculation Asys = Ksys + \ Csys*gamma/(beta*dt) + \ Msys/(beta*dt**2) #Compute correction DQ[:] = np.dot(np.linalg.inv(Asys), -Qsys) Q += DQ dQdt += DQ * gamma / (beta * dt) dQddt += DQ / (beta * dt**2) #Update convergence criteria if XBOPTS.PrintInfo.value == True: sys.stdout.write('%-10.4e ' % (max(abs(Qsys)))) Res_Qglobal = max(abs(Qsys)) Res_DeltaX = max(abs(DQ)) ResLog10 = max(Res_Qglobal / Res0_Qglobal, Res_DeltaX / Res0_DeltaX) if XBOPTS.PrintInfo.value == True: sys.stdout.write('%-10.4e %8.4f\n' % (max(abs(DQ)), ResLog10)) #END Netwon-Raphson #update to converged nodal displacements and velocities X = Q[:NumDof.value].copy('F') dXdt = dQdt[:NumDof.value].copy('F') BeamLib.Cbeam3_Solv_State2Disp(XBINPUT, NumNodes_tot, XBELEM, XBNODE, PosIni, PsiIni, NumDof, X, dXdt,\ PosDefor, PsiDefor, PosDotDef, PsiDotDef) PosPsiTime[iStep + 1, :3] = PosDefor[(NumNodes_tot.value - 1) / 2 + 1, :] PosPsiTime[iStep + 1, 3:] = PsiDefor[-1, XBELEM.NumNodes[-1] - 1, :] #Position of all grid points in global FoR i1 = (iStep + 1) * NumNodes_tot.value i2 = (iStep + 2) * NumNodes_tot.value DynOut[i1:i2, :] = PosDefor #Export rigid-body velocities/accelerations if XBOPTS.OutInaframe.value == True: Vrel[iStep + 1, :] = dQdt[NumDof.value:NumDof.value + 6].copy('F') VrelDot[iStep + 1, :] = dQddt[NumDof.value:NumDof.value + 6].copy('F') else: Quat = dQdt[NumDof.value + 6:].copy('F') Quat = Quat / np.linalg.norm(Quat) Cao = XbeamLib.Rot(Quat) ACoa[:3, :3] = np.transpose(Cao) ACoa[3:, 3:] = np.transpose(Cao) Vrel[iStep + 1, :] = np.dot( ACoa, dQdt[NumDof.value:NumDof.value + 6].copy('F')) VrelDot[iStep + 1, :] = np.dot( ACoa, dQddt[NumDof.value:NumDof.value + 6].copy('F')) #END Time loop #Write _dyn file ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL912_dyn.dat' fp = open(ofile, 'w') BeamIO.Write_dyn_File(fp, Time, PosPsiTime) fp.close() #Write _shape file ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL912_shape.dat' fp = open(ofile, 'w') BeamIO.Write_shape_File(fp, len(Time), NumNodes_tot.value, Time, DynOut) fp.close() #Write rigid-body velocities ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL912_rigid.dat' fp = open(ofile, 'w') BeamIO.Write_rigid_File(fp, Time, Vrel, VrelDot) fp.close() if XBOPTS.PrintInfo.value == True: sys.stdout.write(' ... done\n')
def Solve_Py(XBINPUT,XBOPTS): """Nonlinear dynamic structural solver in Python. Assembly of matrices is carried out with Fortran subroutines.""" #Check correct solution code assert XBOPTS.Solution.value == 912, ('NonlinearDynamic requested' +\ ' with wrong solution code') #Initialise beam XBINPUT, XBOPTS, NumNodes_tot, XBELEM, PosIni, PsiIni, XBNODE, NumDof \ = BeamInit.Static(XBINPUT,XBOPTS) #Solve static XBOPTS.Solution.value = 112 PosDefor, PsiDefor = Solve_Py_Static(XBINPUT,XBOPTS) XBOPTS.Solution.value = 912 #Write deformed configuration to file ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL912_def.dat' if XBOPTS.PrintInfo==True: sys.stdout.write('Writing file %s ... ' %(ofile)) fp = open(ofile,'w') fp.write('TITLE="Non-linear static solution: deformed geometry"\n') fp.write('VARIABLES="iElem" "iNode" "Px" "Py" "Pz" "Rx" "Ry" "Rz"\n') fp.close() if XBOPTS.PrintInfo==True: sys.stdout.write('done\n') WriteMode = 'a' BeamIO.OutputElems(XBINPUT.NumElems, NumNodes_tot.value, XBELEM, \ PosDefor, PsiDefor, ofile, WriteMode) #Initialise variables for dynamic analysis Time, NumSteps, ForceTime, Vrel, VrelDot,\ PosDotDef, PsiDotDef,\ OutGrids, PosPsiTime, VelocTime, DynOut\ = BeamInit.Dynamic(XBINPUT,XBOPTS) # Delete unused variables. del OutGrids, VelocTime #Write _force file ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL912_force.dat' fp = open(ofile,'w') BeamIO.Write_force_File(fp, Time, ForceTime, Vrel, VrelDot) fp.close() if XBOPTS.PrintInfo.value==True: sys.stdout.write('Solve nonlinear dynamic case in Python ... \n') #Initialise structural system tensors MssFull = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F') CssFull = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F') KssFull = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F') FstrucFull = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F') ms = ct.c_int() cs = ct.c_int() ks = ct.c_int() fs = ct.c_int() Msr = np.zeros((NumDof.value,6), ct.c_double, 'F') Csr = np.zeros((NumDof.value,6), ct.c_double, 'F') X = np.zeros(NumDof.value, ct.c_double, 'F') dXdt = np.zeros(NumDof.value, ct.c_double, 'F') Force_Dof = np.zeros(NumDof.value, ct.c_double, 'F') Qstruc = np.zeros(NumDof.value, ct.c_double, 'F') #Initialise rigid-body system tensors MrsFull = np.zeros((6,NumDof.value), ct.c_double, 'F') CrsFull = np.zeros((6,NumDof.value), ct.c_double, 'F') KrsFull = np.zeros((6,NumDof.value), ct.c_double, 'F') FrigidFull = np.zeros((6,NumDof.value+6), ct.c_double, 'F') mr = ct.c_int() cr = ct.c_int() kr = ct.c_int() fr = ct.c_int() Mrr = np.zeros((6,6), ct.c_double, 'F') Crr = np.zeros((6,6), ct.c_double, 'F') Qrigid = np.zeros(6, ct.c_double, 'F') #Initialise full system tensors Q = np.zeros(NumDof.value+6+4, ct.c_double, 'F') DQ = np.zeros(NumDof.value+6+4, ct.c_double, 'F') dQdt = np.zeros(NumDof.value+6+4, ct.c_double, 'F') dQddt = np.zeros(NumDof.value+6+4, ct.c_double, 'F') Force_All = np.zeros(NumDof.value+6, ct.c_double, 'F') Msys = np.zeros((NumDof.value+6+4,NumDof.value+6+4), ct.c_double, 'F') Csys = np.zeros((NumDof.value+6+4,NumDof.value+6+4), ct.c_double, 'F') Ksys = np.zeros((NumDof.value+6+4,NumDof.value+6+4), ct.c_double, 'F') Asys = np.zeros((NumDof.value+6+4,NumDof.value+6+4), ct.c_double, 'F') Qsys = np.zeros(NumDof.value+6+4, ct.c_double, 'F') #Initialise rotation operators Quat = np.zeros(4, ct.c_double, 'F'); Quat[0] = 1.0 Cao = XbeamLib.Rot(Quat) ACoa = np.zeros((6,6), ct.c_double, 'F') Cqr = np.zeros((4,6), ct.c_double, 'F') Cqq = np.zeros((4,4), ct.c_double, 'F') Unit4 = np.zeros((4,4), ct.c_double, 'F') for i in range(4): Unit4[i,i] = 1.0 #Extract initial displacements and velocities BeamLib.Cbeam_Solv_Disp2State(NumNodes_tot, NumDof, XBINPUT, XBNODE,\ PosDefor, PsiDefor, PosDotDef, PsiDotDef, X, dXdt) #Initialise accelerations as zero arrays PosDotDotDef = np.zeros((NumNodes_tot.value,3),ct.c_double,'F') PsiDotDotDef = np.zeros((XBINPUT.NumElems,Settings.MaxElNod,3),\ ct.c_double, 'F') #Populate state vector Q[:NumDof.value]=X.copy('F') dQdt[:NumDof.value]=dXdt.copy('F') dQdt[NumDof.value:NumDof.value+6] = Vrel[0,:].copy('F') dQdt[NumDof.value+6:]= Quat.copy('F') #Force at the first time-step Force = (XBINPUT.ForceStatic + XBINPUT.ForceDyn*ForceTime[0]).copy('F') #Assemble matrices and loads for structural dynamic analysis tmpVrel=Vrel[0,:].copy('F') tmpQuat=Quat.copy('F') BeamLib.Cbeam3_Asbly_Dynamic(XBINPUT, NumNodes_tot, XBELEM, XBNODE,\ PosIni, PsiIni, PosDefor, PsiDefor,\ PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef,\ Force, tmpVrel, 0*tmpVrel,\ NumDof, Settings.DimMat,\ ms, MssFull, Msr,\ cs, CssFull, Csr,\ ks, KssFull, fs, FstrucFull,\ Qstruc, XBOPTS, Cao) BeamLib.f_fem_m2v(ct.byref(NumNodes_tot),\ ct.byref(ct.c_int(6)),\ Force.ctypes.data_as(ct.POINTER(ct.c_double)),\ ct.byref(NumDof),\ Force_Dof.ctypes.data_as(ct.POINTER(ct.c_double)),\ XBNODE.Vdof.ctypes.data_as(ct.POINTER(ct.c_int)) ) Qstruc -= np.dot(FstrucFull, Force_Dof) #Assemble matrices for rigid-body dynamic analysis BeamLib.Xbeam_Asbly_Dynamic(XBINPUT, NumNodes_tot, XBELEM, XBNODE,\ PosIni, PsiIni, PosDefor, PsiDefor,\ PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef,\ tmpVrel, 0*tmpVrel, tmpQuat,\ NumDof, Settings.DimMat,\ mr, MrsFull, Mrr,\ cr, CrsFull, Crr, Cqr, Cqq,\ kr, KrsFull, fr, FrigidFull,\ Qrigid, XBOPTS, Cao) BeamLib.f_fem_m2v_nofilter(ct.byref(NumNodes_tot),\ ct.byref(ct.c_int(6)),\ Force.ctypes.data_as(ct.POINTER(ct.c_double)),\ ct.byref(ct.c_int(NumDof.value+6)),\ Force_All.ctypes.data_as(ct.POINTER(ct.c_double)) ) Qrigid -= np.dot(FrigidFull, Force_All) #Separate assembly of follower and dead loads tmpForceTime=ForceTime[0].copy('F') tmpQforces,Dummy,tmpQrigid = XbeamLib.LoadAssembly(XBINPUT, XBELEM, XBNODE, XBOPTS, NumDof, \ PosIni, PsiIni, PosDefor, PsiDefor, \ (XBINPUT.ForceStatic_foll + XBINPUT.ForceDyn_foll*tmpForceTime), \ (XBINPUT.ForceStatic_dead + XBINPUT.ForceDyn_dead*tmpForceTime), \ Cao,1) Qstruc -= tmpQforces Qrigid -= tmpQrigid #Assemble system matrices Msys[:NumDof.value,:NumDof.value] = MssFull.copy('F') Msys[:NumDof.value,NumDof.value:NumDof.value+6] = Msr.copy('F') Msys[NumDof.value:NumDof.value+6,:NumDof.value] = MrsFull.copy('F') Msys[NumDof.value:NumDof.value+6,NumDof.value:NumDof.value+6] = Mrr.copy('F') Msys[NumDof.value+6:,NumDof.value+6:] = Unit4.copy('F') Qsys[:NumDof.value] = Qstruc Qsys[NumDof.value:NumDof.value+6] = Qrigid Qsys[NumDof.value+6:] = np.dot(Cqq,dQdt[NumDof.value+6:]) #Initial Accel dQddt[:] = np.dot(np.linalg.inv(Msys), -Qsys) #Record position of all grid points in global FoR at initial time step DynOut[0:NumNodes_tot.value,:] = PosDefor #Position/rotation of the selected node in initial deformed configuration PosPsiTime[0,:3] = PosDefor[-1,:] PosPsiTime[0,3:] = PsiDefor[-1,XBELEM.NumNodes[-1]-1,:] #Get gamma and beta for Newmark scheme gamma = 0.5 + XBOPTS.NewmarkDamp.value beta = 0.25*(gamma + 0.5)**2 #Time loop for iStep in range(NumSteps.value): if XBOPTS.PrintInfo.value==True: sys.stdout.write(' Time: %-10.4e\n' %(Time[iStep+1])) sys.stdout.write(' SubIter DeltaF DeltaX ResLog10\n') #calculate dt dt = Time[iStep+1] - Time[iStep] #Predictor step Q += dt*dQdt + (0.5-beta)*dQddt*dt**2 dQdt += (1.0-gamma)*dQddt*dt dQddt[:] = 0.0 #Force at current time-step Force = (XBINPUT.ForceStatic + \ XBINPUT.ForceDyn*ForceTime[iStep+1]).copy('F') #Reset convergence parameters Iter = 0 ResLog10 = 1.0 #Newton-Raphson loop while ( (ResLog10 > XBOPTS.MinDelta.value) \ & (Iter < XBOPTS.MaxIterations.value) ): #set tensors to zero MssFull[:,:] = 0.0; CssFull[:,:] = 0.0 KssFull[:,:] = 0.0; FstrucFull[:,:] = 0.0 Msr[:,:] = 0.0; Csr[:,:] = 0.0 Qstruc[:] = 0.0 MrsFull[:,:] = 0.0; CrsFull[:,:] = 0.0 KrsFull[:,:] = 0.0; FrigidFull[:,:] = 0.0 Mrr[:,:] = 0.0; Crr[:,:] = 0.0 Qrigid[:] = 0.0 Msys[:,:] = 0.0; Csys[:,:] = 0.0 Ksys[:,:] = 0.0; Asys[:,:] = 0.0; Qsys[:] = 0.0 #Update counter Iter += 1 if XBOPTS.PrintInfo.value==True: sys.stdout.write(' %-7d ' %(Iter)) #nodal diplacements and velocities from state vector X=Q[:NumDof.value].copy('F') dXdt=dQdt[:NumDof.value].copy('F'); BeamLib.Cbeam3_Solv_State2Disp(XBINPUT, NumNodes_tot, XBELEM, XBNODE, PosIni, PsiIni, NumDof, X, dXdt,\ PosDefor, PsiDefor, PosDotDef, PsiDotDef) #rigid-body velocities and orientation from state vector Vrel[iStep+1,:] = dQdt[NumDof.value:NumDof.value+6].copy('F') VrelDot[iStep+1,:] = dQddt[NumDof.value:NumDof.value+6].copy('F') Quat = dQdt[NumDof.value+6:].copy('F') Quat = Quat/np.linalg.norm(Quat) Cao = XbeamLib.Rot(Quat) #Assemble matrices and loads for structural dynamic analysis tmpVrel=Vrel[iStep+1,:].copy('F') tmpQuat=Quat.copy('F') BeamLib.Cbeam3_Asbly_Dynamic(XBINPUT, NumNodes_tot, XBELEM, XBNODE,\ PosIni, PsiIni, PosDefor, PsiDefor,\ PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef,\ Force, tmpVrel, 0*tmpVrel,\ NumDof, Settings.DimMat,\ ms, MssFull, Msr,\ cs, CssFull, Csr,\ ks, KssFull, fs, FstrucFull,\ Qstruc, XBOPTS, Cao) BeamLib.f_fem_m2v(ct.byref(NumNodes_tot),\ ct.byref(ct.c_int(6)),\ Force.ctypes.data_as(ct.POINTER(ct.c_double)),\ ct.byref(NumDof),\ Force_Dof.ctypes.data_as(ct.POINTER(ct.c_double)),\ XBNODE.Vdof.ctypes.data_as(ct.POINTER(ct.c_int)) ) #Assemble matrices for rigid-body dynamic analysis BeamLib.Xbeam_Asbly_Dynamic(XBINPUT, NumNodes_tot, XBELEM, XBNODE,\ PosIni, PsiIni, PosDefor, PsiDefor,\ PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef,\ tmpVrel, 0*tmpVrel, tmpQuat,\ NumDof, Settings.DimMat,\ mr, MrsFull, Mrr,\ cr, CrsFull, Crr, Cqr, Cqq,\ kr, KrsFull, fs, FrigidFull,\ Qrigid, XBOPTS, Cao) BeamLib.f_fem_m2v_nofilter(ct.byref(NumNodes_tot),\ ct.byref(ct.c_int(6)),\ Force.ctypes.data_as(ct.POINTER(ct.c_double)),\ ct.byref(ct.c_int(NumDof.value+6)),\ Force_All.ctypes.data_as(ct.POINTER(ct.c_double)) ) #Residual at first iteration if(Iter == 1): Res0_Qglobal = max(max(abs(Qsys)),1) Res0_DeltaX = max(max(abs(DQ)),1) #Assemble discrete system matrices with linearised quaternion equations Msys[:NumDof.value,:NumDof.value] = MssFull.copy('F') Msys[:NumDof.value,NumDof.value:NumDof.value+6] = Msr.copy('F') Msys[NumDof.value:NumDof.value+6,:NumDof.value] = MrsFull.copy('F') Msys[NumDof.value:NumDof.value+6,NumDof.value:NumDof.value+6] = Mrr.copy('F') Msys[NumDof.value+6:,NumDof.value+6:] = Unit4.copy('F') Csys[:NumDof.value,:NumDof.value] = CssFull.copy('F') Csys[:NumDof.value,NumDof.value:NumDof.value+6] = Csr.copy('F') Csys[NumDof.value:NumDof.value+6,:NumDof.value] = CrsFull.copy('F') Csys[NumDof.value:NumDof.value+6,NumDof.value:NumDof.value+6] = Crr.copy('F') Csys[NumDof.value+6:,NumDof.value:NumDof.value+6] = Cqr.copy('F') Csys[NumDof.value+6:,NumDof.value+6:] = Cqq.copy('F') Ksys[:NumDof.value,:NumDof.value] = KssFull.copy('F') Ksys[NumDof.value:NumDof.value+6,:NumDof.value] = KrsFull.copy('F') #Separate assembly of follower and dead loads tmpForceTime=ForceTime[iStep+1].copy('F') tmpQforces,Dummy,tmpQrigid = XbeamLib.LoadAssembly(XBINPUT, XBELEM, XBNODE, XBOPTS, NumDof, \ PosIni, PsiIni, PosDefor, PsiDefor, \ (XBINPUT.ForceStatic_foll + XBINPUT.ForceDyn_foll*tmpForceTime), \ (XBINPUT.ForceStatic_dead + XBINPUT.ForceDyn_dead*tmpForceTime), \ Cao,1) Qstruc -= tmpQforces Qrigid -= tmpQrigid #Compute residual Qstruc += -np.dot(FstrucFull, Force_Dof) Qrigid += -np.dot(FrigidFull, Force_All) Qsys[:NumDof.value] = Qstruc Qsys[NumDof.value:NumDof.value+6] = Qrigid Qsys[NumDof.value+6:] = np.dot(Cqq,dQdt[NumDof.value+6:]) Qsys += np.dot(Msys,dQddt) #Calculate system matrix for update calculation Asys = Ksys + \ Csys*gamma/(beta*dt) + \ Msys/(beta*dt**2) #Compute correction DQ[:] = np.dot(np.linalg.inv(Asys), -Qsys) Q += DQ dQdt += DQ*gamma/(beta*dt) dQddt += DQ/(beta*dt**2) #Update convergence criteria if XBOPTS.PrintInfo.value==True: sys.stdout.write('%-10.4e ' %(max(abs(Qsys)))) Res_Qglobal = max(abs(Qsys)) Res_DeltaX = max(abs(DQ)) ResLog10 = max(Res_Qglobal/Res0_Qglobal,Res_DeltaX/Res0_DeltaX) if XBOPTS.PrintInfo.value==True: sys.stdout.write('%-10.4e %8.4f\n' %(max(abs(DQ)),ResLog10)) #END Netwon-Raphson #update to converged nodal displacements and velocities X=Q[:NumDof.value].copy('F') dXdt=dQdt[:NumDof.value].copy('F'); BeamLib.Cbeam3_Solv_State2Disp(XBINPUT, NumNodes_tot, XBELEM, XBNODE, PosIni, PsiIni, NumDof, X, dXdt,\ PosDefor, PsiDefor, PosDotDef, PsiDotDef) PosPsiTime[iStep+1,:3] = PosDefor[(NumNodes_tot.value-1)/2+1,:] PosPsiTime[iStep+1,3:] = PsiDefor[-1,XBELEM.NumNodes[-1]-1,:] #Position of all grid points in global FoR i1 = (iStep+1)*NumNodes_tot.value i2 = (iStep+2)*NumNodes_tot.value DynOut[i1:i2,:] = PosDefor #Export rigid-body velocities/accelerations if XBOPTS.OutInaframe.value==True: Vrel[iStep+1,:] = dQdt[NumDof.value:NumDof.value+6].copy('F') VrelDot[iStep+1,:] = dQddt[NumDof.value:NumDof.value+6].copy('F') else: Quat = dQdt[NumDof.value+6:].copy('F') Quat = Quat/np.linalg.norm(Quat) Cao = XbeamLib.Rot(Quat) ACoa[:3,:3] = np.transpose(Cao) ACoa[3:,3:] = np.transpose(Cao) Vrel[iStep+1,:] = np.dot(ACoa,dQdt[NumDof.value:NumDof.value+6].copy('F')) VrelDot[iStep+1,:] = np.dot(ACoa,dQddt[NumDof.value:NumDof.value+6].copy('F')) #END Time loop #Write _dyn file ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL912_dyn.dat' fp = open(ofile,'w') BeamIO.Write_dyn_File(fp, Time, PosPsiTime) fp.close() #Write _shape file ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL912_shape.dat' fp = open(ofile,'w') BeamIO.Write_shape_File(fp, len(Time), NumNodes_tot.value, Time, DynOut) fp.close() #Write rigid-body velocities ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL912_rigid.dat' fp = open(ofile,'w') BeamIO.Write_rigid_File(fp, Time, Vrel, VrelDot) fp.close() if XBOPTS.PrintInfo.value==True: sys.stdout.write(' ... done\n')
def assemble_GEBM_tensors( iStep, NumDof, NumNodes_tot, XBELEM, XBNODE, XBINPUT, VMINPUT, XBOPTS, AELAOPTS, VMOPTS, tmpVrel, PosIni, PsiIni, PosDefor, PsiDefor, PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef, Force, #? MssFull, CssFull, KssFull, FstrucFull, Msr, Csr, Force_Dof, Qstruc, MrsFull, CrsFull, KrsFull, FrigidFull, Mrr, Crr, Qrigid, Q, dQdt, dQddt, Force_All, Msys, Csys, Ksys, Asys, Qsys ): # utilities: # (dummy variables to store unused output from assembly functions) ms, mr = ct.c_int(), ct.c_int() cs, cr = ct.c_int(), ct.c_int() ks, kr = ct.c_int(), ct.c_int() fs, fr = ct.c_int(), ct.c_int() #set tensors to zero MssFull[:,:] = 0.0; CssFull[:,:] = 0.0 KssFull[:,:] = 0.0; FstrucFull[:,:] = 0.0 Msr[:,:] = 0.0; Csr[:,:] = 0.0 Qstruc[:] = 0.0 MrsFull[:,:] = 0.0; CrsFull[:,:] = 0.0 KrsFull[:,:] = 0.0; FrigidFull[:,:] = 0.0 Mrr[:,:] = 0.0; Crr[:,:] = 0.0 Qrigid[:] = 0.0 Msys[:,:],Csys[:,:],Ksys[:,:],Asys[:,:],Qsys[:] = 0.0,0.0,0.0,0.0,0.0 #rigid-body velocities and orientation from state vector Quat = dQdt[NumDof.value+6:].copy('F') Quat = Quat/np.linalg.norm(Quat) Cao = xbl.Rot(Quat) # input for xbeam assembly Cqr = np.zeros((4,6), ct.c_double, 'F') # dummy: output for xbeam assembly Cqq = np.zeros((4,4), ct.c_double, 'F') # dummy: output for xbeam assembly #Update matrices and loads for structural dynamic analysis tmpQuat=Quat.copy('F') BeamLib.Cbeam3_Asbly_Dynamic(XBINPUT, NumNodes_tot, XBELEM, XBNODE, # in PosIni, PsiIni, PosDefor, PsiDefor, # in PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef, # in Force, tmpVrel, 0*tmpVrel, # in NumDof, Settings.DimMat, # out ms, MssFull, Msr, # out cs, CssFull, Csr, # out ks, KssFull, fs, FstrucFull,Qstruc, # out XBOPTS, Cao) # in BeamLib.f_fem_m2v(ct.byref(NumNodes_tot), ct.byref(ct.c_int(6)), Force.ctypes.data_as(ct.POINTER(ct.c_double)), ct.byref(NumDof), Force_Dof.ctypes.data_as(ct.POINTER(ct.c_double)), XBNODE.Vdof.ctypes.data_as(ct.POINTER(ct.c_int)) ) #Update matrices for rigid-body dynamic analysis BeamLib.Xbeam_Asbly_Dynamic(XBINPUT, NumNodes_tot, XBELEM, XBNODE, # in PosIni, PsiIni, PosDefor, PsiDefor, # in PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef, # in tmpVrel, 0*tmpVrel, tmpQuat, # in NumDof, Settings.DimMat, # out mr, MrsFull, Mrr, # out cr, CrsFull, Crr, Cqr, Cqq, # out kr, KrsFull, fr, FrigidFull, Qrigid, # out XBOPTS, Cao) # in BeamLib.f_fem_m2v_nofilter(ct.byref(NumNodes_tot), ct.byref(ct.c_int(6)), Force.ctypes.data_as(ct.POINTER(ct.c_double)), ct.byref(ct.c_int(NumDof.value+6)), Force_All.ctypes.data_as(ct.POINTER(ct.c_double)) ) #Assemble discrete system matrices with linearised quaternion equations Unit4 = np.zeros((4,4), ct.c_double, 'F') for i in range(4): Unit4[i,i] = 1.0 Msys[:NumDof.value,:NumDof.value] = MssFull.copy('F') Msys[:NumDof.value,NumDof.value:NumDof.value+6] = Msr.copy('F') Msys[NumDof.value:NumDof.value+6,:NumDof.value] = MrsFull.copy('F') Msys[NumDof.value:NumDof.value+6,NumDof.value:NumDof.value+6] = Mrr.copy('F') Msys[NumDof.value+6:,NumDof.value+6:] = Unit4.copy('F') Csys[:NumDof.value,:NumDof.value] = CssFull.copy('F') Csys[:NumDof.value,NumDof.value:NumDof.value+6] = Csr.copy('F') Csys[NumDof.value:NumDof.value+6,:NumDof.value] = CrsFull.copy('F') Csys[NumDof.value:NumDof.value+6,NumDof.value:NumDof.value+6] = Crr.copy('F') Csys[NumDof.value+6:,NumDof.value:NumDof.value+6] = Cqr.copy('F') Csys[NumDof.value+6:,NumDof.value+6:] = Cqq.copy('F') Ksys[:NumDof.value,:NumDof.value] = KssFull.copy('F') Ksys[NumDof.value:NumDof.value+6,:NumDof.value] = KrsFull.copy('F') #Separate assembly of follower and dead loads #tmpForceTime=ForceTime[iStep+1].copy('F') tmpQforces,Dummy,tmpQrigid = xbl.LoadAssembly(XBINPUT, XBELEM, XBNODE, XBOPTS, NumDof, PosIni, PsiIni, PosDefor, PsiDefor, (XBINPUT.ForceStatic_foll + XBINPUT.ForceDyn_foll[iStep,:,:] ), (XBINPUT.ForceStatic_dead + XBINPUT.ForceDyn_dead[iStep,:,:] ), Cao,1) Qstruc -= tmpQforces Qrigid -= tmpQrigid #Compute residual to solve update vector Qstruc -= np.dot(FstrucFull, Force_Dof) Qrigid -= np.dot(FrigidFull, Force_All) Qsys[:NumDof.value] = Qstruc Qsys[NumDof.value:NumDof.value+6] = Qrigid Qsys[NumDof.value+6:] = np.dot(Cqq,dQdt[NumDof.value+6:]) Qsys += np.dot(Msys,dQddt) # include damping if XBINPUT.str_damping_model == 'prop': Cdamp = XBINPUT.str_damping_param['alpha'] * MssFull + \ XBINPUT.str_damping_param['beta'] * KssFull Csys[:NumDof.value,:NumDof.value] += Cdamp Qsys[:NumDof.value] += np.dot(Cdamp, dQdt[:NumDof.value]) #---------------------------------------------------------------------------------- special BCs iiblock=[] if XBNODE.Sflag.any(): # block translations (redundant:) for ii in range(3): if XBINPUT.EnforceTraVel_FoRA[ii] == True: iiblock.append(NumDof.value+ii) # block rotations iirotfree=[] # free rotational dof for ii in range(3): if XBINPUT.EnforceAngVel_FoRA[ii] is True: iiblock.append(NumDof.value+3+ii) else: iirotfree.append(NumDof.value+3+ii) if len(iiblock)>0: Msys[iiblock,:] = 0.0 Msys[:,iiblock] = 0.0 Msys[iiblock,iiblock] = 1.0 Csys[iiblock,:] = 0.0 Ksys[iiblock,:] = 0.0 Qsys[iiblock] = 0.0 if XBINPUT.sph_joint_damping is not None: Csys[iirotfree,iirotfree] += XBINPUT.sph_joint_damping Qsys[iirotfree] += XBINPUT.sph_joint_damping*dQdt[iirotfree] return Msys, Csys, Ksys, Qsys
def Solve_Py(XBINPUT,XBOPTS, moduleName = None): """Nonlinear static solver using Python to solve residual equation. Assembly of matrices is carried out with Fortran subroutines.""" "Check correct solution code" assert XBOPTS.Solution.value == 112, ('NonlinearStatic requested' +\ ' with wrong solution code') "Initialise beam" XBINPUT, XBOPTS, NumNodes_tot, XBELEM, PosIni, PsiIni, XBNODE, NumDof \ = BeamInit.Static(XBINPUT,XBOPTS, moduleName) "Set initial conditions as undef config" PosDefor = PosIni.copy(order='F') PsiDefor = PsiIni.copy(order='F') if XBOPTS.PrintInfo.value==True: sys.stdout.write('Solve nonlinear static case in Python ... \n') "Initialise rotation operators" Unit = np.zeros((3,3), ct.c_double, 'F') for i in range(3): Unit[i,i] = 1.0 Cao = Unit.copy('F') "Initialise structural eqn tensors" KglobalFull = np.zeros((NumDof.value,NumDof.value),\ ct.c_double, 'F'); ks = ct.c_int() KglobalFull_foll = np.zeros((NumDof.value,NumDof.value),\ ct.c_double, 'F'); FglobalFull = np.zeros((NumDof.value,NumDof.value),\ ct.c_double, 'F'); fs = ct.c_int() DeltaS = np.zeros(NumDof.value, ct.c_double, 'F') Qglobal = np.zeros(NumDof.value, ct.c_double, 'F') x = np.zeros(NumDof.value, ct.c_double, 'F') dxdt = np.zeros(NumDof.value, ct.c_double, 'F') "Load Step tensors" iForceStep = np.zeros((NumNodes_tot.value,6), ct.c_double, 'F') iForceStep_Dof = np.zeros(NumDof.value, ct.c_double, 'F') "Start Load Loop" for iLoadStep in range(XBOPTS.NumLoadSteps.value): "Reset convergence parameters" Iter = 0 ResLog10 = 1.0 "General load case" iForceStep = XBINPUT.ForceStatic*float( (iLoadStep+1) / \ XBOPTS.NumLoadSteps.value) if XBOPTS.PrintInfo.value == True: sys.stdout.write(' iLoad: %-10d\n' %(iLoadStep+1)) sys.stdout.write(' SubIter DeltaF DeltaX ResLog10\n') "Newton Iteration" while( (ResLog10 > XBOPTS.MinDelta.value) \ & (Iter < XBOPTS.MaxIterations.value) ): "Increment iteration counter" Iter += 1 if XBOPTS.PrintInfo.value == True: sys.stdout.write(' %-7d ' %(Iter)) "Set structural eqn tensors to zero" KglobalFull[:,:] = 0.0; ks = ct.c_int() KglobalFull_foll[:,:] = 0.0; FglobalFull[:,:] = 0.0; fs = ct.c_int() Qglobal[:] = 0.0 "Assemble matrices for static problem" BeamLib.Cbeam3_Asbly_Static(XBINPUT, NumNodes_tot, XBELEM, XBNODE,\ PosIni, PsiIni, PosDefor, PsiDefor,\ iForceStep, NumDof,\ ks, KglobalFull, fs, FglobalFull, Qglobal,\ XBOPTS) "Get state vector from current deformation" PosDot = np.zeros((NumNodes_tot.value,3), ct.c_double, 'F') #R PsiDot = np.zeros((XBINPUT.NumElems,Settings.MaxElNod,3),\ ct.c_double, 'F') #Psi BeamLib.Cbeam_Solv_Disp2State(NumNodes_tot, NumDof, XBINPUT, XBNODE,\ PosDefor, PsiDefor, PosDot, PsiDot, x, dxdt) "Get forces on unconstrained nodes" BeamLib.f_fem_m2v(ct.byref(NumNodes_tot),\ ct.byref(ct.c_int(6)),\ iForceStep.ctypes.data_as(ct.POINTER(ct.c_double)),\ ct.byref(NumDof),\ iForceStep_Dof.ctypes.data_as(ct.POINTER(ct.c_double)),\ XBNODE.Vdof.ctypes.data_as(ct.POINTER(ct.c_int)) ) "Calculate \Delta RHS" Qglobal = Qglobal - np.dot(FglobalFull, iForceStep_Dof) "Separate assembly of follower and dead loads" Qforces, KglobalFull_foll = \ XbeamLib.LoadAssembly(XBINPUT, XBELEM, XBNODE, XBOPTS, NumDof, \ PosIni, PsiIni, PosDefor, PsiDefor, \ XBINPUT.ForceStatic_foll,XBINPUT.ForceStatic_dead, \ Cao, float((iLoadStep+1)/XBOPTS.NumLoadSteps.value))[:2] KglobalFull += KglobalFull_foll Qglobal -= Qforces "Calculate \Delta State Vector" DeltaS = - np.dot(np.linalg.inv(KglobalFull), Qglobal) if XBOPTS.PrintInfo.value == True: sys.stdout.write('%-10.4e %-10.4e ' \ % (max(abs(Qglobal)),max(abs(DeltaS)))) "Update Solution" BeamLib.Cbeam3_Solv_Update_Static(XBINPUT, NumNodes_tot, XBELEM,\ XBNODE, NumDof, DeltaS,\ PosIni, PsiIni, PosDefor,PsiDefor) "Residual at first iteration" if(Iter == 1): Res0_Qglobal = max(max(abs(Qglobal)),1) Res0_DeltaX = max(max(abs(DeltaS)),1) "Update residual and compute log10" Res_Qglobal = max(abs(Qglobal)) Res_DeltaX = max(abs(DeltaS)) ResLog10 = max(Res_Qglobal/Res0_Qglobal, Res_DeltaX/Res0_DeltaX) if XBOPTS.PrintInfo.value == True: sys.stdout.write('%8.4f\n' %(ResLog10)) "Stop the solution" if(ResLog10 > 1.e10): sys.stderr.write(' STOP\n') sys.stderr.write(' The max residual is %e\n' %(ResLog10)) exit(1) "END Newton Loop" "END Load Loop" if XBOPTS.PrintInfo.value==True: sys.stdout.write(' ... done\n') "Write deformed configuration to file" ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL112_def.dat' if XBOPTS.PrintInfo.value==True: sys.stdout.write('Writing file %s ... ' %(ofile)) fp = open(ofile,'w') fp.write('TITLE="Non-linear static solution: deformed geometry"\n') fp.write('VARIABLES="iElem" "iNode" "Px" "Py" "Pz" "Rx" "Ry" "Rz"\n') fp.close() if XBOPTS.PrintInfo.value==True: sys.stdout.write('done\n') WriteMode = 'a' BeamIO.OutputElems(XBINPUT.NumElems, NumNodes_tot.value, XBELEM, \ PosDefor, PsiDefor, ofile, WriteMode) "Print deformed configuration" if XBOPTS.PrintInfo.value==True: sys.stdout.write('--------------------------------------\n') sys.stdout.write('NONLINEAR STATIC SOLUTION\n') sys.stdout.write('%10s %10s %10s\n' %('X','Y','Z')) for inodi in range(NumNodes_tot.value): sys.stdout.write(' ') for inodj in range(3): sys.stdout.write('%12.5e' %(PosDefor[inodi,inodj])) sys.stdout.write('\n') sys.stdout.write('--------------------------------------\n') "Return solution as optional output argument" return PosDefor, PsiDefor
def Solve_Py(XBINPUT,XBOPTS): """Nonlinear static solver using Python to solve residual equation. Assembly of matrices is carried out with Fortran subroutines.""" "Check correct solution code" assert XBOPTS.Solution.value == 112, ('NonlinearStatic requested' +\ ' with wrong solution code') "Initialise beam" XBINPUT, XBOPTS, NumNodes_tot, XBELEM, PosIni, PsiIni, XBNODE, NumDof \ = BeamInit.Static(XBINPUT,XBOPTS) "Set initial conditions as undef config" PosDefor = PosIni.copy(order='F') PsiDefor = PsiIni.copy(order='F') if XBOPTS.PrintInfo.value==True: sys.stdout.write('Solve nonlinear static case in Python ... \n') "Initialise structural eqn tensors" KglobalFull = np.zeros((NumDof.value,NumDof.value),\ ct.c_double, 'F'); ks = ct.c_int() FglobalFull = np.zeros((NumDof.value,NumDof.value),\ ct.c_double, 'F'); fs = ct.c_int() DeltaS = np.zeros(NumDof.value, ct.c_double, 'F') Qglobal = np.zeros(NumDof.value, ct.c_double, 'F') x = np.zeros(NumDof.value, ct.c_double, 'F') dxdt = np.zeros(NumDof.value, ct.c_double, 'F') "Load Step tensors" iForceStep = np.zeros((NumNodes_tot.value,6), ct.c_double, 'F') iForceStep_Dof = np.zeros(NumDof.value, ct.c_double, 'F') "Start Load Loop" for iLoadStep in range(XBOPTS.NumLoadSteps.value): "Reset convergence parameters" Iter = 0 ResLog10 = 0.0 iForceStep = XBINPUT.ForceStatic*float( (iLoadStep+1) / \ XBOPTS.NumLoadSteps.value) if XBOPTS.PrintInfo.value == True: sys.stdout.write(' iLoad: %-10d\n' %(iLoadStep+1)) sys.stdout.write(' SubIter DeltaF DeltaX ResLog10\n') "Newton Iteration" while( (ResLog10 > np.log10(XBOPTS.MinDelta.value)) \ & (Iter < XBOPTS.MaxIterations.value) ): "Increment iteration counter" Iter += 1 if XBOPTS.PrintInfo.value == True: sys.stdout.write(' %-7d ' %(Iter)) "Set structural eqn tensors to zero" KglobalFull[:,:] = 0.0; ks = ct.c_int() FglobalFull[:,:] = 0.0; fs = ct.c_int() Qglobal[:] = 0.0 "Assemble matrices for static problem" BeamLib.Cbeam3_Asbly_Static(XBINPUT, NumNodes_tot, XBELEM, XBNODE,\ PosIni, PsiIni, PosDefor, PsiDefor,\ iForceStep, NumDof,\ ks, KglobalFull, fs, FglobalFull, Qglobal,\ XBOPTS) "Get state vector from current deformation" PosDot = np.zeros((NumNodes_tot.value,3), ct.c_double, 'F') #R PsiDot = np.zeros((XBINPUT.NumElems,Settings.MaxElNod,3),\ ct.c_double, 'F') #Psi BeamLib.Cbeam_Solv_Disp2State(NumNodes_tot, NumDof, XBINPUT, XBNODE,\ PosDefor, PsiDefor, PosDot, PsiDot, x, dxdt) "Get forces on unconstrained nodes" BeamLib.f_fem_m2v(ct.byref(NumNodes_tot),\ ct.byref(ct.c_int(6)),\ iForceStep.ctypes.data_as(ct.POINTER(ct.c_double)),\ ct.byref(NumDof),\ iForceStep_Dof.ctypes.data_as(ct.POINTER(ct.c_double)),\ XBNODE.Vdof.ctypes.data_as(ct.POINTER(ct.c_int)) ) "Calculate \Delta RHS" Qglobal = Qglobal - np.dot(FglobalFull, iForceStep_Dof) "Calculate \Delta State Vector" DeltaS = - np.dot(np.linalg.inv(KglobalFull), Qglobal) if XBOPTS.PrintInfo.value == True: sys.stdout.write('%-10.4e %-10.4e ' \ % (max(abs(Qglobal)),max(abs(DeltaS)))) "Update Solution" BeamLib.Cbeam3_Solv_Update_Static(XBINPUT, NumNodes_tot, XBELEM,\ XBNODE, NumDof, DeltaS,\ PosIni, PsiIni, PosDefor,PsiDefor) "Residual at first iteration" if(Iter == 1): Res0_Qglobal = max(abs(Qglobal)) + 1.e-16 Res0_DeltaX = max(abs(DeltaS)) + 1.e-16 "Update residual and compute log10" Res_Qglobal = max(abs(Qglobal)) + 1.e-16 Res_DeltaX = max(abs(DeltaS)) + 1.e-16 ResLog10 = max([np.log10(Res_Qglobal/Res0_Qglobal), \ np.log10(Res_DeltaX/Res0_DeltaX)]) if XBOPTS.PrintInfo.value == True: sys.stdout.write('%8.4f\n' %(ResLog10)) "Stop the solution" if(ResLog10 > 10.): sys.stderr.write(' STOP\n') sys.stderr.write(' The max residual is %e\n' %(ResLog10)) exit(1) "END Newton Loop" "END Load Loop" if XBOPTS.PrintInfo.value==True: sys.stdout.write(' ... done\n') "Write deformed configuration to file" ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL112_def.dat' if XBOPTS.PrintInfo.value==True: sys.stdout.write('Writing file %s ... ' %(ofile)) fp = open(ofile,'w') fp.write('TITLE="Non-linear static solution: deformed geometry"\n') fp.write('VARIABLES="iElem" "iNode" "Px" "Py" "Pz" "Rx" "Ry" "Rz"\n') fp.close() if XBOPTS.PrintInfo.value==True: sys.stdout.write('done\n') WriteMode = 'a' BeamIO.OutputElems(XBINPUT.NumElems, NumNodes_tot.value, XBELEM, \ PosDefor, PsiDefor, ofile, WriteMode) "Print deformed configuration" if XBOPTS.PrintInfo.value==True: sys.stdout.write('--------------------------------------\n') sys.stdout.write('NONLINEAR STATIC SOLUTION\n') sys.stdout.write('%10s %10s %10s\n' %('X','Y','Z')) for inodi in range(NumNodes_tot.value): sys.stdout.write(' ') for inodj in range(3): sys.stdout.write('%12.5e' %(PosDefor[inodi,inodj])) sys.stdout.write('\n') sys.stdout.write('--------------------------------------\n') "Return solution as optional output argument" return PosDefor, PsiDefor
def assemble_GEBM_tensors( iStep, NumDof, Nconstr, NumNodes_tot, XBELEM, XBNODE, XBINPUT, VMINPUT, XBOPTS, AELAOPTS, VMOPTS, tmpVrel, PosIni, PsiIni, PosDefor, PsiDefor, PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef, Force, #? MssFull, CssFull, KssFull, FstrucFull, Msr, Csr, Force_Dof, Qstruc, MrsFull, CrsFull, KrsFull, FrigidFull, Mrr, Crr, Qrigid, Q, dQdt, dQddt, Force_All, Msys, Csys, Ksys, Asys, Qsys ): Nsys = NumDof.value+10+Nconstr # utilities: # (dummy variables to store unused output from assembly functions) ms, mr = ct.c_int(), ct.c_int() cs, cr = ct.c_int(), ct.c_int() ks, kr = ct.c_int(), ct.c_int() fs, fr = ct.c_int(), ct.c_int() #set tensors to zero MssFull[:,:] = 0.0; CssFull[:,:] = 0.0 KssFull[:,:] = 0.0; FstrucFull[:,:] = 0.0 Msr[:,:] = 0.0; Csr[:,:] = 0.0 Qstruc[:] = 0.0 MrsFull[:,:] = 0.0; CrsFull[:,:] = 0.0 KrsFull[:,:] = 0.0; FrigidFull[:,:] = 0.0 Mrr[:,:] = 0.0; Crr[:,:] = 0.0 Qrigid[:] = 0.0 Msys[:,:],Csys[:,:],Ksys[:,:],Asys[:,:],Qsys[:] = 0.0,0.0,0.0,0.0,0.0 #rigid-body velocities and orientation from state vector Quat = dQdt[NumDof.value+6:NumDof.value+10].copy('F') Quat = Quat/np.linalg.norm(Quat) Cao = xbl.Rot(Quat) # input for xbeam assembly Cqr = np.zeros((4,6), ct.c_double, 'F') # dummy: output for xbeam assembly Cqq = np.zeros((4,4), ct.c_double, 'F') # dummy: output for xbeam assembly #Update matrices and loads for structural dynamic analysis tmpQuat=Quat.copy('F') BeamLib.Cbeam3_Asbly_Dynamic(XBINPUT, NumNodes_tot, XBELEM, XBNODE, # in PosIni, PsiIni, PosDefor, PsiDefor, # in PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef, # in Force, tmpVrel, 0*tmpVrel, # in NumDof, Settings.DimMat, # out ms, MssFull, Msr, # out cs, CssFull, Csr, # out ks, KssFull, fs, FstrucFull,Qstruc, # out XBOPTS, Cao) # in BeamLib.f_fem_m2v(ct.byref(NumNodes_tot), ct.byref(ct.c_int(6)), Force.ctypes.data_as(ct.POINTER(ct.c_double)), ct.byref(NumDof), Force_Dof.ctypes.data_as(ct.POINTER(ct.c_double)), XBNODE.Vdof.ctypes.data_as(ct.POINTER(ct.c_int)) ) #Update matrices for rigid-body dynamic analysis BeamLib.Xbeam_Asbly_Dynamic(XBINPUT, NumNodes_tot, XBELEM, XBNODE, # in PosIni, PsiIni, PosDefor, PsiDefor, # in PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef, # in tmpVrel, 0*tmpVrel, tmpQuat, # in NumDof, Settings.DimMat, # out mr, MrsFull, Mrr, # out cr, CrsFull, Crr, Cqr, Cqq, # out kr, KrsFull, fr, FrigidFull, Qrigid, # out XBOPTS, Cao) # in BeamLib.f_fem_m2v_nofilter(ct.byref(NumNodes_tot), ct.byref(ct.c_int(6)), Force.ctypes.data_as(ct.POINTER(ct.c_double)), ct.byref(ct.c_int(NumDof.value+6)), Force_All.ctypes.data_as(ct.POINTER(ct.c_double)) ) #Assemble discrete system matrices with linearised quaternion equations Unit4 = np.zeros((4,4), ct.c_double, 'F') for i in range(4): Unit4[i,i] = 1.0 Msys[:NumDof.value,:NumDof.value] = MssFull.copy('F') Msys[:NumDof.value,NumDof.value:NumDof.value+6] = Msr.copy('F') Msys[NumDof.value:NumDof.value+6,:NumDof.value] = MrsFull.copy('F') Msys[NumDof.value:NumDof.value+6,NumDof.value:NumDof.value+6] = Mrr.copy('F') Msys[NumDof.value+6:NumDof.value+10,NumDof.value+6:NumDof.value+10] = Unit4.copy('F') Csys[:NumDof.value,:NumDof.value] = CssFull.copy('F') Csys[:NumDof.value,NumDof.value:NumDof.value+6] = Csr.copy('F') Csys[NumDof.value:NumDof.value+6,:NumDof.value] = CrsFull.copy('F') Csys[NumDof.value:NumDof.value+6,NumDof.value:NumDof.value+6] = Crr.copy('F') Csys[NumDof.value+6:NumDof.value+10,NumDof.value:NumDof.value+6] = Cqr.copy('F') Csys[NumDof.value+6:NumDof.value+10,NumDof.value+6:NumDof.value+10] = Cqq.copy('F') Ksys[:NumDof.value,:NumDof.value] = KssFull.copy('F') Ksys[NumDof.value:NumDof.value+6,:NumDof.value] = KrsFull.copy('F') #Separate assembly of follower and dead loads #tmpForceTime=ForceTime[iStep+1].copy('F') tmpQforces,Dummy,tmpQrigid = xbl.LoadAssembly(XBINPUT, XBELEM, XBNODE, XBOPTS, NumDof, PosIni, PsiIni, PosDefor, PsiDefor, (XBINPUT.ForceStatic_foll + XBINPUT.ForceDyn_foll[iStep,:,:] ), (XBINPUT.ForceStatic_dead + XBINPUT.ForceDyn_dead[iStep,:,:] ), Cao,1) Qstruc -= tmpQforces Qrigid -= tmpQrigid #Compute residual to solve update vector Qstruc -= np.dot(FstrucFull, Force_Dof) Qrigid -= np.dot(FrigidFull, Force_All) Qsys[:NumDof.value] = Qstruc Qsys[NumDof.value:NumDof.value+6] = Qrigid Qsys[NumDof.value+6:NumDof.value+10] = np.dot(Cqq,dQdt[NumDof.value+6:NumDof.value+10]) Qsys += np.dot(Msys,dQddt) # include damping if XBINPUT.str_damping_model == 'prop': Cdamp = XBINPUT.str_damping_param['alpha'] * MssFull + \ XBINPUT.str_damping_param['beta'] * KssFull Csys[:NumDof.value,:NumDof.value] += Cdamp Qsys[:NumDof.value] += np.dot(Cdamp, dQdt[:NumDof.value]) #---------------------------------------------------------------------------------- special BCs iiblock=[] if XBNODE.Sflag.any(): # find perpendicular vectors to axis of rotation XBINPUT.rvers=XBINPUT.rvers/np.linalg.norm(XBINPUT.rvers) nvec=0 for ii in range(3): svers = np.zeros((3,)) if XBINPUT.rvers[ii]<1e-9: svers[ii]=1.0 break #else: # raise NameError('Develop robust way to find perpendicular vectors') if np.all(np.abs(svers)<1e-9): raise NameError('Develop robust way to find perpendicular vectors') tvers=np.cross(XBINPUT.rvers,svers) #print('rvers:'+3*' %.3f'%tuple(XBINPUT.rvers)) #print('svers:'+3*' %.3f'%tuple(svers)) #print('tvers:'+3*' %.3f'%tuple(tvers)) #1/0 # block translations (redundant:) for ii in range(3): if XBINPUT.EnforceTraVel_FoRA[ii] == True: iiblock.append(NumDof.value+ii) ##### block rotations #iirotfree=[] # free rotational dof #for ii in range(3): # if XBINPUT.EnforceAngVel_FoRA[ii] is True: # iiblock.append(NumDof.value+3+ii) # else: iirotfree.append(NumDof.value+3+ii) #iirotfree=[NumDof.value+3+ii for ii in range(3)] # to add damping # augment system AugMat = 0.0*Msys # improve efficiency: preallocate this matrix B = np.zeros((Nconstr,Nsys-Nconstr)) B[0,NumDof.value+3:NumDof.value+6]=svers B[1,NumDof.value+3:NumDof.value+6]=tvers BT=B.transpose() #BTB=np.dot(BT,B) AugMat[:Nsys-Nconstr,:Nsys-Nconstr]=XBINPUT.AugLagr_p*np.dot(BT,B) AugMat[:Nsys-Nconstr,Nsys-Nconstr:]=XBINPUT.AugLagr_k*BT AugMat[Nsys-Nconstr:,:Nsys-Nconstr]=XBINPUT.AugLagr_k*B # block translational dof if len(iiblock)>0: Msys[iiblock,:] = 0.0 Msys[:,iiblock] = 0.0 Msys[iiblock,iiblock] = 1.0 Csys[iiblock,:] = 0.0 Ksys[iiblock,:] = 0.0 Qsys[iiblock] = 0.0 if XBINPUT.sph_joint_damping is not None: iirotfree=[NumDof.value+3+ii for ii in range(3)] Csys[iirotfree,iirotfree] += XBINPUT.sph_joint_damping Qsys[iirotfree] += XBINPUT.sph_joint_damping*dQdt[iirotfree] # Augment Mass Matrix Msys += AugMat #Csys += AugMat return Msys, Csys, Ksys, Qsys
def Solve_Py(XBINPUT,XBOPTS,VMOPTS,VMINPUT,AELAOPTS): """Nonlinear static solver using Python to solve aeroelastic equation. Assembly of structural matrices is carried out with Fortran subroutines. Aerodynamics solved using PyAero.UVLM.""" assert XBOPTS.Solution.value == 112, ('NonlinearStatic requested' + ' with wrong solution code') # Initialize beam. XBINPUT, XBOPTS, NumNodes_tot, XBELEM, PosIni, PsiIni, XBNODE, NumDof \ = BeamInit.Static(XBINPUT,XBOPTS) # Set initial conditions as undef config. PosDefor = PosIni.copy(order='F') PsiDefor = PsiIni.copy(order='F') if XBOPTS.PrintInfo.value==True: sys.stdout.write('Solve nonlinear static case in Python ... \n') # Initialise structural eqn tensors. KglobalFull = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F'); ks = ct.c_int() FglobalFull = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F'); fs = ct.c_int() DeltaS = np.zeros(NumDof.value, ct.c_double, 'F') Qglobal = np.zeros(NumDof.value, ct.c_double, 'F') x = np.zeros(NumDof.value, ct.c_double, 'F') dxdt = np.zeros(NumDof.value, ct.c_double, 'F') # Beam Load Step tensors iForceStep = np.zeros((NumNodes_tot.value,6), ct.c_double, 'F') iForceStep_Dof = np.zeros(NumDof.value, ct.c_double, 'F') # Initialze Aero. Section = InitSection(VMOPTS,VMINPUT,AELAOPTS.ElasticAxis) # Declare memory for Aero grid and velocities. Zeta = np.zeros((Section.shape[0],PosDefor.shape[0],3),ct.c_double,'C') ZetaDot = np.zeros((Section.shape[0],PosDefor.shape[0],3),ct.c_double,'C') # Additional Aero solver variables. AeroForces = np.zeros((VMOPTS.M.value+1,VMOPTS.N.value+1,3),ct.c_double,'C') Gamma = np.zeros((VMOPTS.M.value,VMOPTS.N.value),ct.c_double,'C') # Init external velocities. Uext = InitSteadyExternalVels(VMOPTS,VMINPUT) # Create zero triads for motion of reference frame. VelA_A = np.zeros((3)) OmegaA_A = np.zeros((3)) # Create zero vectors for structural vars not used in static analysis. PosDotDef = np.zeros_like(PosDefor, ct.c_double, 'F') PsiDotDef = np.zeros_like(PsiDefor, ct.c_double, 'F') # Define tecplot stuff. FileName = Settings.OutputDir + Settings.OutputFileRoot + 'AeroGrid.dat' Variables = ['X', 'Y', 'Z','Gamma'] FileObject = PostProcess.WriteAeroTecHeader(FileName, 'Default', Variables) # Start Load Loop. for iLoadStep in range(XBOPTS.NumLoadSteps.value): # Reset convergence parameters and loads. Iter = 0 ResLog10 = 0.0 XBINPUT.ForceStatic[:,:] = 0.0 AeroForces[:,:,:] = 0.0 # Calculate aero loads. if hasattr(XBINPUT, 'ForcedVel'): CoincidentGrid(PosDefor, PsiDefor, Section, XBINPUT.ForcedVel[0,:3], XBINPUT.ForcedVel[0,3:], PosDotDef, PsiDotDef, XBINPUT, Zeta, ZetaDot, ctrlSurf = VMINPUT.ctrlSurf) else: CoincidentGrid(PosDefor, PsiDefor, Section, VelA_A, OmegaA_A, PosDotDef, PsiDotDef, XBINPUT, Zeta, ZetaDot, ctrlSurf = VMINPUT.ctrlSurf) if hasattr(XBINPUT,'ForcedVel'): ZetaStar, GammaStar = InitSteadyWake(VMOPTS,VMINPUT,Zeta,XBINPUT.ForcedVel[0,:3]) else: ZetaStar, GammaStar = InitSteadyWake(VMOPTS,VMINPUT,Zeta) # Solve for AeroForces. UVLMLib.Cpp_Solver_VLM(Zeta, ZetaDot, Uext, ZetaStar, VMOPTS, AeroForces, Gamma, GammaStar) AeroForces[:,:,:] = AELAOPTS.AirDensity*AeroForces[:,:,:] # Write solution to tecplot file. PostProcess.WriteUVLMtoTec(FileObject, Zeta, ZetaStar, Gamma, GammaStar, iLoadStep, XBOPTS.NumLoadSteps.value, iLoadStep*1.0, Text = True) # Map AeroForces to beam. CoincidentGridForce(XBINPUT, PsiDefor, Section, AeroForces, XBINPUT.ForceStatic) # Add gravity loads. AddGravityLoads(XBINPUT.ForceStatic,XBINPUT,XBELEM,AELAOPTS, PsiDefor,VMINPUT.c) # Apply factor corresponding to force step. iForceStep = XBINPUT.ForceStatic*float( (iLoadStep+1) ) / \ XBOPTS.NumLoadSteps.value if XBOPTS.PrintInfo.value == True: sys.stdout.write(' iLoad: %-10d\n' %(iLoadStep+1)) sys.stdout.write(' SubIter DeltaF DeltaX ResLog10\n') # Start Newton Iteration. while( (ResLog10 > np.log10(XBOPTS.MinDelta.value)) & (Iter < XBOPTS.MaxIterations.value) ): Iter += 1 if XBOPTS.PrintInfo.value == True: sys.stdout.write(' %-7d ' %(Iter)) # Set structural eqn tensors to zero KglobalFull[:,:] = 0.0; ks = ct.c_int() FglobalFull[:,:] = 0.0; fs = ct.c_int() Qglobal[:] = 0.0 # Assemble matrices for static problem BeamLib.Cbeam3_Asbly_Static(XBINPUT, NumNodes_tot, XBELEM, XBNODE, PosIni, PsiIni, PosDefor, PsiDefor, iForceStep, NumDof, ks, KglobalFull, fs, FglobalFull, Qglobal, XBOPTS) # Get state vector from current deformation. PosDot = np.zeros((NumNodes_tot.value,3), ct.c_double, 'F') PsiDot = np.zeros((XBINPUT.NumElems,Settings.MaxElNod,3), ct.c_double, 'F') BeamLib.Cbeam_Solv_Disp2State(NumNodes_tot, NumDof, XBINPUT, XBNODE, PosDefor, PsiDefor, PosDot, PsiDot, x, dxdt) # Get forces on unconstrained nodes. BeamLib.f_fem_m2v(ct.byref(NumNodes_tot), ct.byref(ct.c_int(6)), iForceStep.ctypes.data_as(ct.POINTER(ct.c_double)), ct.byref(NumDof), iForceStep_Dof.ctypes.data_as(ct.POINTER(ct.c_double)), XBNODE.Vdof.ctypes.data_as(ct.POINTER(ct.c_int)) ) # Calculate \Delta RHS. Qglobal = Qglobal - np.dot(FglobalFull, iForceStep_Dof) # Calculate \Delta State Vector. DeltaS = - np.dot(np.linalg.inv(KglobalFull), Qglobal) if XBOPTS.PrintInfo.value == True: sys.stdout.write('%-10.4e %-10.4e ' % (max(abs(Qglobal)),max(abs(DeltaS)))) # Update Solution. BeamLib.Cbeam3_Solv_Update_Static(XBINPUT, NumNodes_tot, XBELEM, XBNODE, NumDof, DeltaS, PosIni, PsiIni, PosDefor, PsiDefor) # Record residual at first iteration. if(Iter == 1): Res0_Qglobal = max(abs(Qglobal)) + 1.e-16 Res0_DeltaX = max(abs(DeltaS)) + 1.e-16 # Update residual and compute log10 Res_Qglobal = max(abs(Qglobal)) + 1.e-16 Res_DeltaX = max(abs(DeltaS)) + 1.e-16 ResLog10 = max([np.log10(Res_Qglobal/Res0_Qglobal), np.log10(Res_DeltaX/Res0_DeltaX)] ) if XBOPTS.PrintInfo.value == True: sys.stdout.write('%8.4f\n' %(ResLog10)) # Stop the solution. if(ResLog10 > 10.): sys.stderr.write(' STOP\n') sys.stderr.write(' The max residual is %e\n' %(ResLog10)) exit(1) elif Res_DeltaX < 1.e-14: break # END Newton iteration # END Load step loop if XBOPTS.PrintInfo.value==True: sys.stdout.write(' ... done\n') # Write deformed configuration to file. ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL112_def.dat' if XBOPTS.PrintInfo.value==True: sys.stdout.write('Writing file %s ... ' %(ofile)) fp = open(ofile,'w') fp.write('TITLE="Non-linear static solution: deformed geometry"\n') fp.write('VARIABLES="iElem" "iNode" "Px" "Py" "Pz" "Rx" "Ry" "Rz"\n') fp.close() if XBOPTS.PrintInfo.value==True: sys.stdout.write('done\n') WriteMode = 'a' BeamIO.OutputElems(XBINPUT.NumElems, NumNodes_tot.value, XBELEM, PosDefor, PsiDefor, ofile, WriteMode) # Print deformed configuration. if XBOPTS.PrintInfo.value==True: sys.stdout.write('--------------------------------------\n') sys.stdout.write('NONLINEAR STATIC SOLUTION\n') sys.stdout.write('%10s %10s %10s\n' %('X','Y','Z')) for inodi in range(NumNodes_tot.value): sys.stdout.write(' ') for inodj in range(3): sys.stdout.write('%12.5e' %(PosDefor[inodi,inodj])) sys.stdout.write('\n') sys.stdout.write('--------------------------------------\n') # Close Tecplot ascii FileObject. PostProcess.CloseAeroTecFile(FileObject) # Return solution return PosDefor, PsiDefor, Zeta, ZetaStar, Gamma, GammaStar, iForceStep
def Solve_Py(XBINPUT,XBOPTS, moduleName = None, SaveDict=Settings.SaveDict): """Nonlinear dynamic structural solver in Python. Assembly of matrices is carried out with Fortran subroutines.""" #"Check correct solution code" assert XBOPTS.Solution.value == 312, ('NonlinearDynamic requested' +\ ' with wrong solution code') # I/O management Settings.SaveDict=SaveDict # overwrite for compatibility with 'dat' format output XBOUT=DerivedTypes.Xboutput() XBOUT.cputime.append(time.clock()) if SaveDict['Format']=='h5': Settings.WriteOut=False Settings.PlotTec=False OutList=[XBOPTS, XBINPUT, XBOUT] #"Initialise beam" XBINPUT, XBOPTS, NumNodes_tot, XBELEM, PosIni, PsiIni, XBNODE, NumDof \ = BeamInit.Static(XBINPUT,XBOPTS, moduleName) # Solve static solution if XBOPTS.ImpStart==True: PosDefor = PosIni.copy(order='F') PsiDefor = PsiIni.copy(order='F') XBOUT.ForceStaticTotal = XBINPUT.ForceStatic.copy('F') AddGravityLoads(XBOUT.ForceStaticTotal,XBINPUT,XBELEM, AELAOPTS=None, # allows defining inertial/elastic axis PsiDefor=PsiDefor, chord = 0.0, # used to define inertial/elastic axis PsiA_G=XBINPUT.PsiA_G, FollowerForceRig=XBOPTS.FollowerForceRig.value) else: XBOPTS.Solution.value = 112 XBSTA = Solve_Py_Static(XBINPUT, XBOPTS, moduleName, SaveDict=SaveDict) XBOPTS.Solution.value = 312 # Define Pos/Psi as fortran array (crash otherwise) PosDefor=XBSTA.PosDeforStatic.copy(order='F') PsiDefor=XBSTA.PsiDeforStatic.copy(order='F') XBOUT.PosDeforStatic=XBSTA.PosDeforStatic XBOUT.PsiDeforStatic=XBSTA.PsiDeforStatic XBOUT.ForceStaticTotal=XBSTA.ForceStaticTotal # includes gravity loads del XBSTA #Write deformed configuration to file if SaveDict['Format']=='dat': ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL912_def.dat' if XBOPTS.PrintInfo==True: sys.stdout.write('Writing file %s ... ' %(ofile)) fp = open(ofile,'w') fp.write('TITLE="Non-linear static solution: deformed geometry"\n') fp.write('VARIABLES="iElem" "iNode" "Px" "Py" "Pz" "Rx" "Ry" "Rz"\n') fp.close() if XBOPTS.PrintInfo==True: sys.stdout.write('done\n') WriteMode = 'a' BeamIO.OutputElems(XBINPUT.NumElems, NumNodes_tot.value, XBELEM, \ PosDefor, PsiDefor, ofile, WriteMode) else: XBOUT.drop( PosIni=PosIni, PsiIni=PsiIni, PosDeforStatic=PosDefor.copy(), PsiDeforStatic=PsiDefor.copy()) PyLibs.io.save.h5file(SaveDict['OutputDir'],SaveDict['OutputFileRoot']+'.h5', *OutList) #"Initialise variables for dynamic analysis" Time, NumSteps, ForceTime, ForcedVel, ForcedVelDot,\ PosDotDef, PsiDotDef,\ OutGrids, PosPsiTime, VelocTime, DynOut\ = BeamInit.Dynamic(XBINPUT,XBOPTS, moduleName) # Delete unused vars del OutGrids, VelocTime #"Write _force file" if SaveDict['Format']=='dat': ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL312_force.dat' fp = open(ofile,'w') BeamIO.Write_force_File(fp, Time, ForceTime, ForcedVel, ForcedVelDot) fp.close() # sm write class XBOUT.Time=Time XBOUT.Vrel=ForcedVel XBOUT.VrelDot=ForcedVelDot if XBOPTS.PrintInfo.value==True: sys.stdout.write('Solve nonlinear dynamic case in Python ... \n') #"Initialise structural system tensors" MglobalFull = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F') CglobalFull = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F') KglobalFull = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F') FglobalFull = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F') Asys = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F') ms = ct.c_int() cs = ct.c_int() ks = ct.c_int() fs = ct.c_int() Mvel = np.zeros((NumDof.value,6), ct.c_double, 'F') Cvel = np.zeros((NumDof.value,6), ct.c_double, 'F') X = np.zeros(NumDof.value, ct.c_double, 'F') DX = np.zeros(NumDof.value, ct.c_double, 'F') dXdt = np.zeros(NumDof.value, ct.c_double, 'F') dXddt = np.zeros(NumDof.value, ct.c_double, 'F') Force_Dof = np.zeros(NumDof.value, ct.c_double, 'F') Qglobal = np.zeros(NumDof.value, ct.c_double, 'F') #"Initialise rotation operators" Unit = np.zeros((3,3), ct.c_double, 'F') for i in range(3): Unit[i,i] = 1.0 Unit4 = np.zeros((4,4), ct.c_double, 'F') for i in range(4): Unit4[i,i] = 1.0 Cao = Unit.copy('F') Temp = Unit4.copy('F') #Quat = np.zeros(4, ct.c_double, 'F') #Quat[0] = 1.0 Quat = psi2quat(XBINPUT.PsiA_G) XBOUT.QuatList.append(Quat) #"Extract initial displacements and velocities" BeamLib.Cbeam_Solv_Disp2State(NumNodes_tot, NumDof, XBINPUT, XBNODE,\ PosDefor, PsiDefor, PosDotDef, PsiDotDef, X, dXdt) #"Approximate initial accelerations" #"Initialise accelerations as zero arrays" PosDotDotDef = np.zeros((NumNodes_tot.value,3),ct.c_double,'F') PsiDotDotDef = np.zeros((XBINPUT.NumElems,Settings.MaxElNod,3),\ ct.c_double, 'F') #"Force at the first time-step" # Note: rank of Force increased after removing ForceTime Force = (XBOUT.ForceStaticTotal + XBINPUT.ForceDyn[0,:,:]).copy('F') #"Assemble matrices for dynamic analysis" BeamLib.Cbeam3_Asbly_Dynamic(XBINPUT, NumNodes_tot, XBELEM, XBNODE,\ PosIni, PsiIni, PosDefor, PsiDefor,\ PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef,\ Force, ForcedVel[0,:], ForcedVelDot[0,:],\ NumDof, Settings.DimMat,\ ms, MglobalFull, Mvel,\ cs, CglobalFull, Cvel,\ ks, KglobalFull, fs, FglobalFull,\ Qglobal, XBOPTS, Cao) #store initial matrices for eigenvalues analysis XBOUT.M0 = MglobalFull.copy() XBOUT.C0 = CglobalFull.copy() XBOUT.K0 = KglobalFull.copy() #"Get force vector for unconstrained nodes (Force_Dof)" BeamLib.f_fem_m2v(ct.byref(NumNodes_tot),\ ct.byref(ct.c_int(6)),\ Force.ctypes.data_as(ct.POINTER(ct.c_double)),\ ct.byref(NumDof),\ Force_Dof.ctypes.data_as(ct.POINTER(ct.c_double)),\ XBNODE.Vdof.ctypes.data_as(ct.POINTER(ct.c_int)) ) #"Get RHS at initial condition" Qglobal += -np.dot(FglobalFull, Force_Dof) #Separate assembly of follower and dead loads" tmpForceTime=ForceTime[0].copy('F') Qforces = XbeamLib.LoadAssembly(XBINPUT, XBELEM, XBNODE, XBOPTS, NumDof, \ PosIni, PsiIni, PosDefor, PsiDefor, \ ### sm increased rank of ForceDyn_* #(XBINPUT.ForceStatic_foll + XBINPUT.ForceDyn_foll*tmpForceTime), \ #(XBINPUT.ForceStatic_dead + XBINPUT.ForceDyn_dead*tmpForceTime), \ (XBINPUT.ForceStatic_foll + XBINPUT.ForceDyn_foll[0,:,:]), \ (XBINPUT.ForceStatic_dead + XBINPUT.ForceDyn_dead[0,:,:]), \ Cao, 1)[0] Qglobal -= Qforces #"Initial Accel" dXddt[:] = np.dot(np.linalg.inv(MglobalFull), -Qglobal) #embed() #dXddt[iiblock]=0.0 #"Record position of all grid points in global FoR at initial time step" DynOut[0:NumNodes_tot.value,:] = PosDefor #"Position/rotation of the selected node in initial deformed configuration" PosPsiTime[0,:3] = PosDefor[-1,:] PosPsiTime[0,3:] = PsiDefor[-1,XBELEM.NumNodes[-1]-1,:] #"Get gamma and beta for Newmark scheme" gamma = 0.5 + XBOPTS.NewmarkDamp.value beta = 0.25*np.power((gamma + 0.5),2.0) #"Time loop" for iStep in range(NumSteps.value): if XBOPTS.PrintInfo.value==True: sys.stdout.write(' Time: %-10.4e\n' %(Time[iStep+1])) sys.stdout.write(' SubIter DeltaF DeltaX ResLog10\n') #"calculate dt" dt = Time[iStep+1] - Time[iStep] #"Update transformation matrix for given angular velocity" Temp = np.linalg.inv(Unit4 + 0.25*XbeamLib.QuadSkew(ForcedVel[iStep+1,3:])*dt) Quat = np.dot(Temp, np.dot(Unit4 - 0.25*XbeamLib.QuadSkew(ForcedVel[iStep,3:])*dt, Quat)) Quat = Quat/np.linalg.norm(Quat) Cao = XbeamLib.Rot(Quat) #"Predictor step" X += dt*dXdt + (0.5-beta)*dXddt*dt**2 dXdt += (1.0-gamma)*dXddt*dt dXddt[:] = 0.0 # Force calculation: moved in while as depending on PsiDefor #Force=(XBINPUT.ForceStatic+XBINPUT.ForceDyn*ForceTime[iStep+1]).copy('F') #Force=(XBINPUT.ForceStatic+XBINPUT.ForceDyn[iStep+1,:,:]).copy('F') #"Reset convergence parameters" Iter = 0 ResLog10 = 1.0 #"Newton-Raphson loop" while ( (ResLog10 > XBOPTS.MinDelta.value) \ & (Iter < XBOPTS.MaxIterations.value) ): #"set tensors to zero" Qglobal[:] = 0.0 Mvel[:,:] = 0.0 Cvel[:,:] = 0.0 MglobalFull[:,:] = 0.0 CglobalFull[:,:] = 0.0 KglobalFull[:,:] = 0.0 FglobalFull[:,:] = 0.0 #"Update counter" Iter += 1 if XBOPTS.PrintInfo.value==True: sys.stdout.write(' %-7d ' %(Iter)) #"nodal diplacements and velocities from state vector" BeamLib.Cbeam3_Solv_State2Disp(XBINPUT, NumNodes_tot, XBELEM, XBNODE, PosIni, PsiIni, NumDof, X, dXdt,\ PosDefor, PsiDefor, PosDotDef, PsiDotDef) # update force Force = (XBINPUT.ForceStatic+XBINPUT.ForceDyn[iStep+1,:,:]).copy('F') AddGravityLoads(Force, XBINPUT, XBELEM, AELAOPTS=None, # allows defining inertial/elastic axis PsiDefor=PsiDefor, chord = 0.0, # used to define inertial/elastic axis PsiA_G=XbeamLib.quat2psi(Quat), FollowerForceRig=XBOPTS.FollowerForceRig.value) #"update matrices" BeamLib.Cbeam3_Asbly_Dynamic(XBINPUT, NumNodes_tot, XBELEM, XBNODE,\ PosIni, PsiIni, PosDefor, PsiDefor,\ PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef,\ Force, ForcedVel[iStep+1,:], ForcedVelDot[iStep+1,:],\ NumDof, Settings.DimMat,\ ms, MglobalFull, Mvel,\ cs, CglobalFull, Cvel,\ ks, KglobalFull, fs, FglobalFull,\ Qglobal, XBOPTS, Cao) #"Get force vector for unconstrained nodes (Force_Dof)" BeamLib.f_fem_m2v(ct.byref(NumNodes_tot),\ ct.byref(ct.c_int(6)),\ Force.ctypes.data_as(ct.POINTER(ct.c_double)),\ ct.byref(NumDof),\ Force_Dof.ctypes.data_as(ct.POINTER(ct.c_double)),\ XBNODE.Vdof.ctypes.data_as(ct.POINTER(ct.c_int)) ) Q1 = np.dot(MglobalFull, dXddt) Q2 = np.dot(Mvel,ForcedVelDot[iStep+1,:]) Q3 = - np.dot(FglobalFull, Force_Dof) #"Solve for update vector" #"Residual" Qglobal += np.dot(MglobalFull, dXddt) \ + np.dot(Mvel,ForcedVelDot[iStep+1,:]) \ - np.dot(FglobalFull, Force_Dof) #Separate assembly of follower and dead loads tmpForceTime=ForceTime[iStep+1].copy('F') Qforces = XbeamLib.LoadAssembly(XBINPUT, XBELEM, XBNODE, XBOPTS, NumDof, \ PosIni, PsiIni, PosDefor, PsiDefor, \ (XBINPUT.ForceStatic_foll + XBINPUT.ForceDyn_foll*tmpForceTime), \ (XBINPUT.ForceStatic_dead + XBINPUT.ForceDyn_dead*tmpForceTime), \ Cao,1)[0] Qglobal -= Qforces if XBOPTS.PrintInfo.value==True: sys.stdout.write('%-10.4e ' %(max(abs(Qglobal)))) #"Calculate system matrix for update calculation" Asys = KglobalFull + \ CglobalFull*gamma/(beta*dt) + \ MglobalFull/(beta*np.power(dt,2.0)) #"Solve for update" DX[:] = np.dot(np.linalg.inv(Asys), -Qglobal) #"Corrector step" X += DX dXdt += DX*gamma/(beta*dt) dXddt += DX/(beta*dt**2) #"Residual at first iteration" if(Iter == 1): Res0_Qglobal = max(max(abs(Qglobal)),1) Res0_DeltaX = max(max(abs(DX)),1) #"Update residual and compute log10" Res_Qglobal = max(abs(Qglobal)) Res_DeltaX = max(abs(DX)) ResLog10 = max(Res_Qglobal/Res0_Qglobal,Res_DeltaX/Res0_DeltaX) if XBOPTS.PrintInfo.value==True: sys.stdout.write('%-10.4e %8.4f\n' %(max(abs(DX)),ResLog10)) #"END Netwon-Raphson" #"update to converged nodal displacements and velocities" BeamLib.Cbeam3_Solv_State2Disp(XBINPUT, NumNodes_tot, XBELEM, XBNODE, PosIni, PsiIni, NumDof, X, dXdt, PosDefor, PsiDefor, PosDotDef, PsiDotDef) PosPsiTime[iStep+1,:3] = PosDefor[(NumNodes_tot.value-1)/2+1,:] PosPsiTime[iStep+1,3:] = PsiDefor[-1,XBELEM.NumNodes[-1]-1,:] #"Position of all grid points in global FoR" i1 = (iStep+1)*NumNodes_tot.value i2 = (iStep+2)*NumNodes_tot.value DynOut[i1:i2,:] = PosDefor # sm I/O: FoR A velocities/accelerations XBOUT.QuatList.append(Quat) XBOUT.DynOut=DynOut XBOUT.PsiList.append(PsiDefor.copy()) XBOUT.cputime.append( time.clock() - XBOUT.cputime[0] ) if SaveDict['SaveProgress'] and SaveDict['Format']=='h5': iisave=np.arange(1,NumSteps.value,np.ceil( NumSteps.value/SaveDict['NumSavePoints'])) if any(iisave==iStep): PyLibs.io.save.h5file(SaveDict['OutputDir'], SaveDict['OutputFileRoot']+'.h5',*OutList) #"END Time loop" if SaveDict['Format'] == 'dat': #"Write _dyn file" ofile = Settings.OutputDir + Settings.OutputFileRoot+'_SOL312_dyn.dat' fp = open(ofile,'w') BeamIO.Write_dyn_File(fp, Time, PosPsiTime) fp.close() #"Write _shape file" ofile = Settings.OutputDir+Settings.OutputFileRoot+'_SOL312_shape.dat' fp = open(ofile,'w') BeamIO.Write_shape_File(fp, len(Time), NumNodes_tot.value, Time, DynOut) fp.close() else: XBINPUT.ForceDyn = XBINPUT.ForceDyn + XBINPUT.ForceDyn_foll + XBINPUT.ForceDyn_dead PyLibs.io.save.h5file(SaveDict['OutputDir'], SaveDict['OutputFileRoot']+'.h5', *OutList) if XBOPTS.PrintInfo.value==True: sys.stdout.write(' ... done\n') return XBOUT
def Solve_Py(XBINPUT,XBOPTS, moduleName = None, SaveDict=Settings.SaveDict): """Nonlinear static solver using Python to solve residual equation. Assembly of matrices is carried out with Fortran subroutines.""" #"Check correct solution code" assert XBOPTS.Solution.value == 112, ('NonlinearStatic requested' +\ ' with wrong solution code') # I/O management Settings.SaveDict=SaveDict # overwrite for compatibility with 'dat' format output XBOUT=DerivedTypes.Xboutput() OutList=[XBOPTS, XBINPUT, XBOUT] #"Initialise beam" XBINPUT, XBOPTS, NumNodes_tot, XBELEM, PosIni, PsiIni, XBNODE, NumDof \ = BeamInit.Static(XBINPUT,XBOPTS, moduleName) # debug XBOUT.xbnode=XBNODE XBOUT.xbelem=XBELEM #"Set initial conditions as undef config" PosDefor = PosIni.copy(order='F') PsiDefor = PsiIni.copy(order='F') if XBOPTS.PrintInfo.value==True: sys.stdout.write('Solve nonlinear static case in Python ... \n') # Determine orientatin of FoR A w.r.t. G (for gravity loads) Quat = psi2quat(XBINPUT.PsiA_G) Cao = Rot(Quat) #"Initialise structural eqn tensors" KglobalFull = np.zeros((NumDof.value,NumDof.value),\ ct.c_double, 'F'); ks = ct.c_int() KglobalFull_foll = np.zeros((NumDof.value,NumDof.value),\ ct.c_double, 'F'); FglobalFull = np.zeros((NumDof.value,NumDof.value),\ ct.c_double, 'F'); fs = ct.c_int() DeltaS = np.zeros(NumDof.value, ct.c_double, 'F') Qglobal = np.zeros(NumDof.value, ct.c_double, 'F') x = np.zeros(NumDof.value, ct.c_double, 'F') dxdt = np.zeros(NumDof.value, ct.c_double, 'F') # Add Gravity XBOUT.ForceStaticTotal = XBINPUT.ForceStatic.copy('F') AddGravityLoads(XBOUT.ForceStaticTotal,XBINPUT,XBELEM, AELAOPTS=None, # allows defining inertial/elastic axis PsiDefor=PsiDefor, chord = 0.0, # used to define inertial/elastic axis PsiA_G=XBINPUT.PsiA_G, FollowerForceRig=XBOPTS.FollowerForceRig.value) #"Load Step tensors" iForceStep = np.zeros((NumNodes_tot.value,6), ct.c_double, 'F') iForceStep_Dof = np.zeros(NumDof.value, ct.c_double, 'F') rpar=1.1 # amplification factor IncrPercent=np.array([ rpar**(ii) for ii in range(XBOPTS.NumLoadSteps.value) ]) step00=1./np.sum(IncrPercent) IncrPercent=IncrPercent*step00 assert np.sum(IncrPercent)-1.0<1e-10, 'Algorithm for determining step-'\ 'size of boundary displacements failed. Try reducing the number of steps' #"Start Load Loop" # NumLoadsSteps doubled if forced displacements are enforced in the solution: # - the first NumLoadsSteps increase the applied load # - the last NumLoadsSteps increase the applied displacements at the boundaries if len(XBINPUT.ForcedDisp)==0: Nsteps = XBOPTS.NumLoadSteps.value else: #NumDispSteps=XBOPTS.NumLoadSteps.value #Nsteps = NumDispSteps+XBOPTS.NumLoadSteps.value Nsteps = 2* XBOPTS.NumLoadSteps.value # At each iLoadStep>=XBOPTS.NumLoadSteps.value, an amount of # displacement, determined through the IncrPercent factor, is enforced # at the boundary. IncrPercent can be arbitrary but should also be such # that the sum of each IncrPercent=1. # The initial steps should be very small, so as to avoid the solution # to jump to a different branch. # Different models are possible: ## equally distributed: requires a lot of loads steps #IncrPercent=1./NumDispSteps*np.ones((NumDispSteps,)) ## exponential distribution: guarantees very small initial steps but # reduces the total number of steps #rpar=1.3 # amplification factor #IncrPercent=np.array([ rpar**(ii) for ii in range(NumDispSteps) ]) #step00=1./np.sum(IncrPercent) #IncrPercent=IncrPercent*step00 XBOUT.CondK=[] #for iLoadStep in range(XBOPTS.NumLoadSteps.value): for iLoadStep in range(Nsteps): #"Reset convergence parameters" Iter = 0 ResLog10 = 1.0 if iLoadStep<XBOPTS.NumLoadSteps.value: # Gradually increase the static load IncrHere=IncrPercent[iLoadStep] iForceStep=iForceStep+IncrHere*XBOUT.ForceStaticTotal # mid node midNode=int((XBINPUT.NumNodesTot-1)/2) #print('R0\tR1\tdR\tRguess\tIncOld\tIncHere') #print(6*'%.4f\t'\ # %( PosDefor_0[midNode,2], # PosDefor_1[midNode,2], # (PosDefor_1-PosDefor_0)[midNode,2], # PosDefor[midNode,2], # IncrPercent[iLoadStep-1], # IncrHere)) else: #if iLoadStep>=XBOPTS.NumLoadSteps.value: # Enforce displacement at the boundary IncrHere=IncrPercent[iLoadStep-XBOPTS.NumLoadSteps.value] # update displacements (also initial guess) print('IncrPercent (displacements are cumulative)=%f' %IncrHere) PosDefor = ForceDisplacement(PosIni,PosDefor,XBINPUT.ForcedDisp, XBINPUT.PsiA_G,factor=IncrHere) # debug forced displacements #import matplotlib.pyplot as plt #plt.plot(PosIni[:,0],PosIni[:,2],'k',marker='s') #plt.plot(PosDefor[:,0],PosDefor[:,2],'r',marker='o') #plt.show() if XBOPTS.PrintInfo.value == True: sys.stdout.write(' iLoad: %-10d\n' %(iLoadStep+1)) sys.stdout.write(' SubIter DeltaF DeltaX ResLog10\n') #"Newton Iteration" while( (ResLog10 > XBOPTS.MinDelta.value) \ & (Iter < XBOPTS.MaxIterations.value) ): #"Increment iteration counter" Iter += 1 if XBOPTS.PrintInfo.value == True: sys.stdout.write(' %-7d ' %(Iter)) #"Set structural eqn tensors to zero" KglobalFull[:,:] = 0.0; ks = ct.c_int() KglobalFull_foll[:,:] = 0.0; FglobalFull[:,:] = 0.0; fs = ct.c_int() Qglobal[:] = 0.0 #"Assemble matrices for static problem" BeamLib.Cbeam3_Asbly_Static(XBINPUT, NumNodes_tot, XBELEM, XBNODE,\ PosIni, PsiIni, PosDefor, PsiDefor,\ iForceStep, NumDof,\ ks, KglobalFull, fs, FglobalFull, Qglobal,\ XBOPTS, Cao) #"Get forces on unconstrained nodes" BeamLib.f_fem_m2v(ct.byref(NumNodes_tot),\ ct.byref(ct.c_int(6)),\ iForceStep.ctypes.data_as(ct.POINTER(ct.c_double)),\ ct.byref(NumDof),\ iForceStep_Dof.ctypes.data_as(ct.POINTER(ct.c_double)),\ XBNODE.Vdof.ctypes.data_as(ct.POINTER(ct.c_int)) ) #"Separate assembly of follower and dead loads" Qforces, KglobalFull_foll = \ XbeamLib.LoadAssembly(XBINPUT, XBELEM, XBNODE, XBOPTS, NumDof, \ PosIni, PsiIni, PosDefor, PsiDefor, \ XBINPUT.ForceStatic_foll,XBINPUT.ForceStatic_dead, \ Cao, float((iLoadStep+1)/XBOPTS.NumLoadSteps.value))[:2] KglobalFull += KglobalFull_foll Qglobal = Qglobal -Qforces -np.dot(FglobalFull,iForceStep_Dof) if iLoadStep==0 and Iter==1: XBOUT.K0=KglobalFull.copy() XBOUT.Q0=Qglobal.copy() #"Calculate \Delta State Vector" DeltaS = - np.linalg.solve(KglobalFull, Qglobal) # @warning: on very stiff problem, using a matrix inversion is more # robust then using np.linalg.solve. A least-squares solver can also # be used. #if np.linalg.cond(KglobalFull)>1e20: # Sol=np.linalg.lstsq(KglobalFull, -Qglobal) # DeltaS=Sol[0] # Krank=Sol[2] # sing_val=Sol[3] # if Krank<NumDof.value: # raise NameError('Singular matrix') #else: # #DeltaS = - np.dot(np.linalg.inv(KglobalFull), Qglobal) # DeltaS = - np.linalg.solve(KglobalFull, Qglobal) if XBOPTS.PrintInfo.value == True: sys.stdout.write(2*'%-10.4e '%(max(abs(Qglobal)), max(abs(DeltaS)))) #Residual at first iteration if(Iter == 1): Res0_Qglobal = max(max(abs(Qglobal)),1) Res0_DeltaX = max(max(abs(DeltaS)),1) #Update residual and compute log10 Res_Qglobal = max(abs(Qglobal)) Res_DeltaX = max(abs(DeltaS)) ResLog10 = max(Res_Qglobal/Res0_Qglobal, Res_DeltaX/Res0_DeltaX) if XBOPTS.PrintInfo.value == True: sys.stdout.write('%8.4f\n' %(ResLog10)) # Update Solution (PosDefor/PsiDefor) for next iter BeamLib.Cbeam3_Solv_Update_Static(XBINPUT, NumNodes_tot, XBELEM,\ XBNODE, NumDof, DeltaS,\ PosIni, PsiIni, PosDefor,PsiDefor) ''' #### Floor constrained Cao=RotCRV(XBINPUT.PsiA_G) for nn in range(NumNodes_tot.value): posG=np.dot(Cao,PosDefor[nn,:]) if posG[2]<0.0: posG[2]=0.0 PosDefor[nn,:]=np.dot(Cao.T,posG) ''' #"Stop the solution" if(ResLog10 > 1.e10): sys.stderr.write(' STOP\n') sys.stderr.write(' The max residual is %e\n' %(ResLog10)) return XBOUT exit(1) #"END Newton Loop" #"END Load Loop" if XBOPTS.PrintInfo.value==True: sys.stdout.write(' ... done\n') # Prepare output XBOUT.drop( PosIni=PosIni,PsiIni=PsiIni,PosDeforStatic=PosDefor.copy(), PsiDeforStatic=PsiDefor.copy(), K=KglobalFull.copy()) #"Print deformed configuration" if XBOPTS.PrintInfo.value==True: sys.stdout.write('--------------------------------------\n') sys.stdout.write('NONLINEAR STATIC SOLUTION\n') sys.stdout.write('%10s %10s %10s\n' %('X','Y','Z')) for inodi in range(NumNodes_tot.value): sys.stdout.write(' ') for inodj in range(3): sys.stdout.write('%12.5e' %(PosDefor[inodi,inodj])) sys.stdout.write('\n') sys.stdout.write('--------------------------------------\n') if SaveDict['Format']=='dat': #"Write deformed configuration to file" ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL112_def.dat' if XBOPTS.PrintInfo.value==True: sys.stdout.write('Writing file %s ... ' %(ofile)) fp = open(ofile,'w') fp.write('TITLE="Non-linear static solution: deformed geometry"\n') fp.write('VARIABLES="iElem" "iNode" "Px" "Py" "Pz" "Rx" "Ry" "Rz"\n') fp.close() if XBOPTS.PrintInfo.value==True: sys.stdout.write('done\n') WriteMode = 'a' BeamIO.OutputElems(XBINPUT.NumElems, NumNodes_tot.value, XBELEM, \ PosDefor, PsiDefor, ofile, WriteMode) else: PyLibs.io.save.h5file(SaveDict['OutputDir'], SaveDict['OutputFileRoot']+'.h5', *OutList) #"Return solution as optional output argument" return XBOUT #PosDefor, PsiDefor
def Solve_Py(XBINPUT, XBOPTS, VMOPTS, VMINPUT, AELAOPTS, **kwords): """@brief Nonlinear dynamic solver using Python to solve aeroelastic equation. @details Assembly of structural matrices is carried out with Fortran subroutines. Aerodynamics solved using PyAero\.UVLM. @warning test outstanding: test for maintaining static deflections in same conditions. TODO: Maintain static deflections in same conditions. @param XBINPUT Beam inputs (for initialization in Python). @param XBOPTS Beam solver options (for Fortran). @param VMOPTS UVLM solver options (for C/C++). @param VMINPUT UVLM solver inputs (for initialization in Python). @param VMUNST Unsteady input information for aero solver. @param AELAOPTS Options relevant to coupled aeroelastic simulations. @param writeDict OrderedDict of 'name':tuple of outputs to write. """ # Check correct solution code. assert XBOPTS.Solution.value == 312, ('NonlinearDynamic requested' + ' with wrong solution code') # Initialise static beam data. XBINPUT, XBOPTS, NumNodes_tot, XBELEM, PosIni, PsiIni, XBNODE, NumDof \ = BeamInit.Static(XBINPUT,XBOPTS) # Calculate initial displacements. if AELAOPTS.ImpStart == False: XBOPTS.Solution.value = 112 # Modify options. VMOPTS.Steady = ct.c_bool(True) Rollup = VMOPTS.Rollup.value VMOPTS.Rollup.value = False # Solve Static Aeroelastic. PosDefor, PsiDefor, Zeta, ZetaStar, Gamma, GammaStar, Force = \ Static.Solve_Py(XBINPUT, XBOPTS, VMOPTS, VMINPUT, AELAOPTS) XBOPTS.Solution.value = 312 # Reset options. VMOPTS.Steady = ct.c_bool(False) VMOPTS.Rollup.value = Rollup elif AELAOPTS.ImpStart == True: PosDefor = PosIni.copy(order='F') PsiDefor = PsiIni.copy(order='F') Force = np.zeros((XBINPUT.NumNodesTot, 6), ct.c_double, 'F') # Write deformed configuration to file. TODO: tidy this away inside function. ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL312_def.dat' if XBOPTS.PrintInfo == True: sys.stdout.write('Writing file %s ... ' % (ofile)) fp = open(ofile, 'w') fp.write('TITLE="Non-linear static solution: deformed geometry"\n') fp.write('VARIABLES="iElem" "iNode" "Px" "Py" "Pz" "Rx" "Ry" "Rz"\n') fp.close() if XBOPTS.PrintInfo == True: sys.stdout.write('done\n') WriteMode = 'a' # Write BeamIO.OutputElems(XBINPUT.NumElems, NumNodes_tot.value, XBELEM, PosDefor, PsiDefor, ofile, WriteMode) # Initialise structural variables for dynamic analysis. Time, NumSteps, ForceTime, ForcedVel, ForcedVelDot,\ PosDotDef, PsiDotDef,\ OutGrids, PosPsiTime, VelocTime, DynOut\ = BeamInit.Dynamic(XBINPUT,XBOPTS) # Delete unused variables. del ForceTime, OutGrids, VelocTime # Write _force file # ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL312_force.dat' # fp = open(ofile,'w') # BeamIO.Write_force_File(fp, Time, ForceTime, ForcedVel, ForcedVelDot) # fp.close() # Write _vel file #TODO: write _vel file # Write .mrb file. #TODO: write .mrb file if XBOPTS.PrintInfo.value == True: sys.stdout.write('Solve nonlinear dynamic case in Python ... \n') # Initialise structural system tensors. MglobalFull = np.zeros((NumDof.value, NumDof.value), ct.c_double, 'F') CglobalFull = np.zeros((NumDof.value, NumDof.value), ct.c_double, 'F') KglobalFull = np.zeros((NumDof.value, NumDof.value), ct.c_double, 'F') FglobalFull = np.zeros((NumDof.value, NumDof.value), ct.c_double, 'F') Asys = np.zeros((NumDof.value, NumDof.value), ct.c_double, 'F') ms = ct.c_int() cs = ct.c_int() ks = ct.c_int() fs = ct.c_int() Mvel = np.zeros((NumDof.value, 6), ct.c_double, 'F') Cvel = np.zeros((NumDof.value, 6), ct.c_double, 'F') # X0 = np.zeros(NumDof.value, ct.c_double, 'F') X = np.zeros(NumDof.value, ct.c_double, 'F') DX = np.zeros(NumDof.value, ct.c_double, 'F') dXdt = np.zeros(NumDof.value, ct.c_double, 'F') dXddt = np.zeros(NumDof.value, ct.c_double, 'F') Force_Dof = np.zeros(NumDof.value, ct.c_double, 'F') Qglobal = np.zeros(NumDof.value, ct.c_double, 'F') # Initialise rotation operators. Unit = np.zeros((3, 3), ct.c_double, 'F') for i in range(3): Unit[i, i] = 1.0 Unit4 = np.zeros((4, 4), ct.c_double, 'F') for i in range(4): Unit4[i, i] = 1.0 Cao = Unit.copy('F') Temp = Unit4.copy('F') Quat = np.zeros(4, ct.c_double, 'F') Quat[0] = 1.0 # Extract initial displacements and velocities. BeamLib.Cbeam_Solv_Disp2State(NumNodes_tot, NumDof, XBINPUT, XBNODE, PosDefor, PsiDefor, PosDotDef, PsiDotDef, X, dXdt) # Approximate initial accelerations. PosDotDotDef = np.zeros((NumNodes_tot.value, 3), ct.c_double, 'F') PsiDotDotDef = np.zeros((XBINPUT.NumElems, Settings.MaxElNod, 3), ct.c_double, 'F') # Assemble matrices for dynamic analysis. BeamLib.Cbeam3_Asbly_Dynamic(XBINPUT, NumNodes_tot, XBELEM, XBNODE, PosIni, PsiIni, PosDefor, PsiDefor, PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef, Force, ForcedVel[0, :], ForcedVelDot[0, :], NumDof, Settings.DimMat, ms, MglobalFull, Mvel, cs, CglobalFull, Cvel, ks, KglobalFull, fs, FglobalFull, Qglobal, XBOPTS, Cao) # Get force vector for unconstrained nodes (Force_Dof). BeamLib.f_fem_m2v(ct.byref(NumNodes_tot), ct.byref(ct.c_int(6)), Force.ctypes.data_as(ct.POINTER(ct.c_double)), ct.byref(NumDof), Force_Dof.ctypes.data_as(ct.POINTER(ct.c_double)), XBNODE.Vdof.ctypes.data_as(ct.POINTER(ct.c_int))) # Get RHS at initial condition. Qglobal = Qglobal - np.dot(FglobalFull, Force_Dof) # Initial Accel. dXddt[:] = np.dot(np.linalg.inv(MglobalFull), -Qglobal) # Record position of all grid points in global FoR at initial time step. DynOut[0:NumNodes_tot.value, :] = PosDefor # Record state of the selected node in initial deformed configuration. PosPsiTime[0, :3] = PosDefor[-1, :] PosPsiTime[0, 3:] = PsiDefor[-1, XBELEM.NumNodes[-1] - 1, :] # Get gamma and beta for Newmark scheme. gamma = 0.5 + XBOPTS.NewmarkDamp.value beta = 0.25 * pow((gamma + 0.5), 2) # Initialize Aero Section = InitSection(VMOPTS, VMINPUT, AELAOPTS.ElasticAxis) # Declare memory for Aero variables. ZetaDot = np.zeros((Section.shape[0], PosDefor.shape[0], 3), ct.c_double, 'C') K = VMOPTS.M.value * VMOPTS.N.value AIC = np.zeros((K, K), ct.c_double, 'C') BIC = np.zeros((K, K), ct.c_double, 'C') AeroForces = np.zeros((VMOPTS.M.value + 1, VMOPTS.N.value + 1, 3), ct.c_double, 'C') # Initialise A-frame location and orientation to be zero OriginA_G = np.zeros(3, ct.c_double, 'C') PsiA_G = np.zeros(3, ct.c_double, 'C') # Init external velocities. Ufree = InitSteadyExternalVels(VMOPTS, VMINPUT) # Init uninit vars if an impulsive start is specified. if AELAOPTS.ImpStart == True: Zeta = np.zeros((Section.shape[0], PosDefor.shape[0], 3), ct.c_double, 'C') Gamma = np.zeros((VMOPTS.M.value, VMOPTS.N.value), ct.c_double, 'C') # Generate surface, wake and gamma matrices. CoincidentGrid(PosDefor, PsiDefor, Section, ForcedVel[0, :3], ForcedVel[0, 3:], PosDotDef, PsiDotDef, XBINPUT, Zeta, ZetaDot, OriginA_G, PsiA_G, VMINPUT.ctrlSurf) # init wake grid and gamma matrix. ZetaStar, GammaStar = InitSteadyWake(VMOPTS, VMINPUT, Zeta, ForcedVel[0, :3]) # Init GammaDot GammaDot = np.zeros_like(Gamma, ct.c_double, 'C') # Define tecplot stuff if Settings.PlotTec == True: FileName = Settings.OutputDir + Settings.OutputFileRoot + 'AeroGrid.dat' Variables = ['X', 'Y', 'Z', 'Gamma'] FileObject = PostProcess.WriteAeroTecHeader(FileName, 'Default', Variables) # Plot results of static analysis PostProcess.WriteUVLMtoTec(FileObject, Zeta, ZetaStar, Gamma, GammaStar, TimeStep=0, NumTimeSteps=XBOPTS.NumLoadSteps.value, Time=0.0, Text=True) # Open output file for writing if 'writeDict' in kwords and Settings.WriteOut == True: fp = OpenOutFile(writeDict, XBOPTS, Settings) # Write initial outputs to file. if 'writeDict' in kwords and Settings.WriteOut == True: WriteToOutFile(writeDict, fp, Time[0], PosDefor, PsiDefor, PosIni, PsiIni, XBELEM, ctrlSurf) # END if write # Time loop. for iStep in range(NumSteps.value): if XBOPTS.PrintInfo.value == True: sys.stdout.write('Time: %-10.4e\n' % (Time[iStep + 1])) sys.stdout.write(' SubIter DeltaF DeltaX ResLog10\n') dt = Time[iStep + 1] - Time[iStep] # Set dt for aero force calcs. VMOPTS.DelTime = ct.c_double(dt) # Save Gamma at iStep. GammaSav = Gamma.copy(order='C') # Force at current time-step if iStep > 0 and AELAOPTS.Tight == False: # zero aero forces. AeroForces[:, :, :] = 0.0 # Update CRV. PsiA_G = BeamLib.Cbeam3_quat2psi(Quat) # CRV at iStep # Update origin. OriginA_G[:] = OriginA_G[:] + ForcedVel[iStep - 1, :3] * dt # Update control surface deflection. if VMINPUT.ctrlSurf != None: if 'mpcCont' in kwords: uOpt = kwords['mpcCont'].getUopt( getState(Gamma, GammaStar, GammaDot, X, dXdt)) VMINPUT.ctrlSurf.update(Time[iStep], uOpt[0, 0]) else: VMINPUT.ctrlSurf.update(Time[iStep]) # Generate surface grid. CoincidentGrid(PosDefor, PsiDefor, Section, ForcedVel[iStep, :3], ForcedVel[iStep, 3:], PosDotDef, PsiDotDef, XBINPUT, Zeta, ZetaDot, OriginA_G, PsiA_G, VMINPUT.ctrlSurf) # Update wake geom #'roll' data. ZetaStar = np.roll(ZetaStar, 1, axis=0) GammaStar = np.roll(GammaStar, 1, axis=0) #overwrite grid points with TE. ZetaStar[0, :] = Zeta[VMOPTS.M.value, :] # overwrite Gamma with TE value from previous timestep. GammaStar[0, :] = Gamma[VMOPTS.M.value - 1, :] # Apply gust velocity. if VMINPUT.gust != None: Utot = Ufree + VMINPUT.gust.Vels(Zeta) else: Utot = Ufree # Solve for AeroForces. UVLMLib.Cpp_Solver_VLM(Zeta, ZetaDot, Utot, ZetaStar, VMOPTS, AeroForces, Gamma, GammaStar, AIC, BIC) # Get GammaDot. GammaDot[:] = Gamma[:] - GammaSav[:] # Apply density scaling. AeroForces[:, :, :] = AELAOPTS.AirDensity * AeroForces[:, :, :] if Settings.PlotTec == True: PostProcess.WriteUVLMtoTec( FileObject, Zeta, ZetaStar, Gamma, GammaStar, TimeStep=iStep, NumTimeSteps=XBOPTS.NumLoadSteps.value, Time=Time[iStep], Text=True) # map AeroForces to beam. CoincidentGridForce(XBINPUT, PsiDefor, Section, AeroForces, Force) # Add gravity loads. AddGravityLoads(Force, XBINPUT, XBELEM, AELAOPTS, PsiDefor, VMINPUT.c) #END if iStep > 0 # Quaternion update for orientation. Temp = np.linalg.inv(Unit4 + 0.25 * XbeamLib.QuadSkew(ForcedVel[iStep + 1, 3:]) * dt) Quat = np.dot( Temp, np.dot(Unit4 - 0.25 * XbeamLib.QuadSkew(ForcedVel[iStep, 3:]) * dt, Quat)) Quat = Quat / np.linalg.norm(Quat) Cao = XbeamLib.Rot(Quat) # transformation matrix at iStep+1 if AELAOPTS.Tight == True: # CRV at iStep+1 PsiA_G = BeamLib.Cbeam3_quat2psi(Quat) # Origin at iStep+1 OriginA_G[:] = OriginA_G[:] + ForcedVel[iStep, :3] * dt # Predictor step. X = X + dt * dXdt + (0.5 - beta) * dXddt * pow(dt, 2.0) dXdt = dXdt + (1.0 - gamma) * dXddt * dt dXddt[:] = 0.0 # Reset convergence parameters. Iter = 0 ResLog10 = 0.0 # Newton-Raphson loop. while ((ResLog10 > np.log10(XBOPTS.MinDelta.value)) & (Iter < XBOPTS.MaxIterations.value)): # set tensors to zero. Qglobal[:] = 0.0 Mvel[:, :] = 0.0 Cvel[:, :] = 0.0 MglobalFull[:, :] = 0.0 CglobalFull[:, :] = 0.0 KglobalFull[:, :] = 0.0 FglobalFull[:, :] = 0.0 # Update counter. Iter += 1 if XBOPTS.PrintInfo.value == True: sys.stdout.write(' %-7d ' % (Iter)) # nodal diplacements and velocities from state vector. BeamLib.Cbeam3_Solv_State2Disp(XBINPUT, NumNodes_tot, XBELEM, XBNODE, PosIni, PsiIni, NumDof, X, dXdt, PosDefor, PsiDefor, PosDotDef, PsiDotDef) # if tightly coupled is on then get new aeroforces. if AELAOPTS.Tight == True: # zero aero forces. AeroForces[:, :, :] = 0.0 # Set gamma at t-1 to saved solution. Gamma[:, :] = GammaSav[:, :] # get new grid. # The rigid-body DoFs (OriginA_G,PsiA_G,ForcedVel) at time step # i+1 are used to converge the aeroelastic equations. CoincidentGrid(PosDefor, PsiDefor, Section, ForcedVel[iStep + 1, :3], ForcedVel[iStep + 1, 3:], PosDotDef, PsiDotDef, XBINPUT, Zeta, ZetaDot, OriginA_G, PsiA_G, VMINPUT.ctrlSurf) # close wake. ZetaStar[0, :] = Zeta[VMOPTS.M.value, :] # save pereference and turn off rollup. Rollup = VMOPTS.Rollup.value VMOPTS.Rollup.value = False # Solve for AeroForces. UVLMLib.Cpp_Solver_VLM(Zeta, ZetaDot, Ufree, ZetaStar, VMOPTS, AeroForces, Gamma, GammaStar, AIC, BIC) # turn rollup back to original preference VMOPTS.Rollup.value = Rollup # apply density scaling. AeroForces[:, :, :] = AELAOPTS.AirDensity * AeroForces[:, :, :] # beam forces. CoincidentGridForce(XBINPUT, PsiDefor, Section, AeroForces, Force) # Add gravity loads. AddGravityLoads(Force, XBINPUT, XBELEM, AELAOPTS, PsiDefor, VMINPUT.c) #END if Tight ForcedVelLoc = ForcedVel[iStep + 1, :].copy('F') ForcedVelDotLoc = ForcedVelDot[iStep + 1, :].copy('F') # Update matrices. BeamLib.Cbeam3_Asbly_Dynamic( XBINPUT, NumNodes_tot, XBELEM, XBNODE, PosIni, PsiIni, PosDefor, PsiDefor, PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef, Force, ForcedVelLoc, ForcedVelDotLoc, NumDof, Settings.DimMat, ms, MglobalFull, Mvel, cs, CglobalFull, Cvel, ks, KglobalFull, fs, FglobalFull, Qglobal, XBOPTS, Cao) # Get force vector for unconstrained nodes (Force_Dof). BeamLib.f_fem_m2v( ct.byref(NumNodes_tot), ct.byref(ct.c_int(6)), Force.ctypes.data_as(ct.POINTER(ct.c_double)), ct.byref(NumDof), Force_Dof.ctypes.data_as(ct.POINTER(ct.c_double)), XBNODE.Vdof.ctypes.data_as(ct.POINTER(ct.c_int))) # Solve for update vector. # Residual. Qglobal = Qglobal + np.dot(MglobalFull, dXddt) \ + np.dot(Mvel,ForcedVelDotLoc) \ - np.dot(FglobalFull, Force_Dof) if XBOPTS.PrintInfo.value == True: sys.stdout.write('%-10.4e ' % (max(abs(Qglobal)))) # Calculate system matrix for update calculation. Asys = KglobalFull \ + CglobalFull*gamma/(beta*dt) \ + MglobalFull/(beta*pow(dt,2.0)) # Solve for update. DX[:] = np.dot(np.linalg.inv(Asys), -Qglobal) # Corrector step. X = X + DX dXdt = dXdt + DX * gamma / (beta * dt) dXddt = dXddt + DX / (beta * pow(dt, 2.0)) # Residual at first iteration. if (Iter == 1): Res0_Qglobal = max(abs(Qglobal)) + 1.e-16 Res0_DeltaX = max(abs(DX)) + 1.e-16 # Update residual and compute log10. Res_Qglobal = max(abs(Qglobal)) + 1.e-16 Res_DeltaX = max(abs(DX)) + 1.e-16 ResLog10 = max([ np.log10(Res_Qglobal / Res0_Qglobal), np.log10(Res_DeltaX / Res0_DeltaX) ]) if XBOPTS.PrintInfo.value == True: sys.stdout.write('%-10.4e %8.4f\n' % (max(abs(DX)), ResLog10)) if ResLog10 > 2.0: print("Residual growing! Exit Newton-Raphson...") break # END Netwon-Raphson. if ResLog10 > 2.0: print("Residual growing! Exit time-loop...") debug = 'here' del debug break # Update to converged nodal displacements and velocities. BeamLib.Cbeam3_Solv_State2Disp(XBINPUT, NumNodes_tot, XBELEM, XBNODE, PosIni, PsiIni, NumDof, X, dXdt, PosDefor, PsiDefor, PosDotDef, PsiDotDef) PosPsiTime[iStep + 1, :3] = PosDefor[-1, :] PosPsiTime[iStep + 1, 3:] = PsiDefor[-1, XBELEM.NumNodes[-1] - 1, :] # Position of all grid points in global FoR. i1 = (iStep + 1) * NumNodes_tot.value i2 = (iStep + 2) * NumNodes_tot.value DynOut[i1:i2, :] = PosDefor # Write selected outputs if 'writeDict' in kwords and Settings.WriteOut == True: WriteToOutFile(writeDict, fp, Time[iStep + 1], PosDefor, PsiDefor, PosIni, PsiIni, XBELEM, ctrlSurf) # END if write. # 'Rollup' due to external velocities. TODO: Must add gusts here! ZetaStar[:, :] = ZetaStar[:, :] + VMINPUT.U_infty * dt if VMINPUT.gust != None: ZetaStar[:, :, :] = ZetaStar[:, :, :] + VMINPUT.gust.Vels( ZetaStar) * dt # END Time loop # Write _dyn file. ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL312_dyn.dat' fp = open(ofile, 'w') BeamIO.Write_dyn_File(fp, Time, PosPsiTime) fp.close() # "Write _shape file" # ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL312_shape.dat' # fp = open(ofile,'w') # BeamIO.Write_shape_File(fp, len(Time), NumNodes_tot.value, Time, DynOut) # fp.close() # Close output file if it exists. if 'writeDict' in kwords and Settings.WriteOut == True: fp.close() # Close Tecplot ascii FileObject. if Settings.PlotTec == True: PostProcess.CloseAeroTecFile(FileObject) if XBOPTS.PrintInfo.value == True: sys.stdout.write(' ... done\n') # For interactive analysis at end of simulation set breakpoint. pass
def Solve_Py(XBINPUT,XBOPTS,VMOPTS,VMINPUT,AELAOPTS,**kwords): """@brief Nonlinear dynamic solver using Python to solve aeroelastic equation. @details Assembly of structural matrices is carried out with Fortran subroutines. Aerodynamics solved using PyAero\.UVLM. @warning test outstanding: test for maintaining static deflections in same conditions. TODO: Maintain static deflections in same conditions. @param XBINPUT Beam inputs (for initialization in Python). @param XBOPTS Beam solver options (for Fortran). @param VMOPTS UVLM solver options (for C/C++). @param VMINPUT UVLM solver inputs (for initialization in Python). @param VMUNST Unsteady input information for aero solver. @param AELAOPTS Options relevant to coupled aeroelastic simulations. kwords: @param writeDict OrderedDict of of outputs to write. @param mpcCont Instance of PyMPC.MPC class. """ # Check correct solution code. assert XBOPTS.Solution.value == 312, ('NonlinearDynamic requested' + ' with wrong solution code') # Initialise static beam data. XBINPUT, XBOPTS, NumNodes_tot, XBELEM, PosIni, PsiIni, XBNODE, NumDof \ = BeamInit.Static(XBINPUT,XBOPTS) # Calculate initial displacements. if AELAOPTS.ImpStart == False: XBOPTS.Solution.value = 112 # Modify options. VMOPTS.Steady = ct.c_bool(True) Rollup = VMOPTS.Rollup.value VMOPTS.Rollup.value = False # Solve Static Aeroelastic. PosDefor, PsiDefor, Zeta, ZetaStar, Gamma, GammaStar, Force = \ Static.Solve_Py(XBINPUT, XBOPTS, VMOPTS, VMINPUT, AELAOPTS) XBOPTS.Solution.value = 312 # Reset options. VMOPTS.Steady = ct.c_bool(False) VMOPTS.Rollup.value = Rollup elif AELAOPTS.ImpStart == True: PosDefor = PosIni.copy(order='F') PsiDefor = PsiIni.copy(order='F') Force = np.zeros((XBINPUT.NumNodesTot,6),ct.c_double,'F') # Write deformed configuration to file. TODO: tidy this away inside function. ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL312_def.dat' if XBOPTS.PrintInfo==True: sys.stdout.write('Writing file %s ... ' %(ofile)) fp = open(ofile,'w') fp.write('TITLE="Non-linear static solution: deformed geometry"\n') fp.write('VARIABLES="iElem" "iNode" "Px" "Py" "Pz" "Rx" "Ry" "Rz"\n') fp.close() if XBOPTS.PrintInfo==True: sys.stdout.write('done\n') WriteMode = 'a' # Write BeamIO.OutputElems(XBINPUT.NumElems, NumNodes_tot.value, XBELEM, PosDefor, PsiDefor, ofile, WriteMode) # Initialise structural variables for dynamic analysis. Time, NumSteps, ForceTime, ForcedVel, ForcedVelDot,\ PosDotDef, PsiDotDef,\ OutGrids, PosPsiTime, VelocTime, DynOut\ = BeamInit.Dynamic(XBINPUT,XBOPTS) # Delete unused variables. del ForceTime, OutGrids, VelocTime # Write _force file # ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL312_force.dat' # fp = open(ofile,'w') # BeamIO.Write_force_File(fp, Time, ForceTime, ForcedVel, ForcedVelDot) # fp.close() # Write _vel file #TODO: write _vel file # Write .mrb file. #TODO: write .mrb file if XBOPTS.PrintInfo.value==True: sys.stdout.write('Solve nonlinear dynamic case in Python ... \n') # Initialise structural system tensors. MglobalFull = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F') CglobalFull = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F') KglobalFull = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F') FglobalFull = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F') Asys = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F') ms = ct.c_int() cs = ct.c_int() ks = ct.c_int() fs = ct.c_int() Mvel = np.zeros((NumDof.value,6), ct.c_double, 'F') Cvel = np.zeros((NumDof.value,6), ct.c_double, 'F') # X0 = np.zeros(NumDof.value, ct.c_double, 'F') X = np.zeros(NumDof.value, ct.c_double, 'F') DX = np.zeros(NumDof.value, ct.c_double, 'F') dXdt = np.zeros(NumDof.value, ct.c_double, 'F') dXddt = np.zeros(NumDof.value, ct.c_double, 'F') Force_Dof = np.zeros(NumDof.value, ct.c_double, 'F') Qglobal = np.zeros(NumDof.value, ct.c_double, 'F') # Initialise rotation operators. Unit = np.zeros((3,3), ct.c_double, 'F') for i in range(3): Unit[i,i] = 1.0 Unit4 = np.zeros((4,4), ct.c_double, 'F') for i in range(4): Unit4[i,i] = 1.0 Cao = Unit.copy('F') Temp = Unit4.copy('F') Quat = np.zeros(4, ct.c_double, 'F') Quat[0] = 1.0 # Extract initial displacements and velocities. BeamLib.Cbeam_Solv_Disp2State(NumNodes_tot, NumDof, XBINPUT, XBNODE, PosDefor, PsiDefor, PosDotDef, PsiDotDef, X, dXdt) # Approximate initial accelerations. PosDotDotDef = np.zeros((NumNodes_tot.value,3),ct.c_double,'F') PsiDotDotDef = np.zeros((XBINPUT.NumElems,Settings.MaxElNod,3), ct.c_double, 'F') # Assemble matrices for dynamic analysis. BeamLib.Cbeam3_Asbly_Dynamic(XBINPUT, NumNodes_tot, XBELEM, XBNODE, PosIni, PsiIni, PosDefor, PsiDefor, PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef, Force, ForcedVel[0,:], ForcedVelDot[0,:], NumDof, Settings.DimMat, ms, MglobalFull, Mvel, cs, CglobalFull, Cvel, ks, KglobalFull, fs, FglobalFull, Qglobal, XBOPTS, Cao) # Get force vector for unconstrained nodes (Force_Dof). BeamLib.f_fem_m2v(ct.byref(NumNodes_tot), ct.byref(ct.c_int(6)), Force.ctypes.data_as(ct.POINTER(ct.c_double)), ct.byref(NumDof), Force_Dof.ctypes.data_as(ct.POINTER(ct.c_double)), XBNODE.Vdof.ctypes.data_as(ct.POINTER(ct.c_int)) ) # Get RHS at initial condition. Qglobal = Qglobal - np.dot(FglobalFull, Force_Dof) # Initial Accel. dXddt[:] = np.dot(np.linalg.inv(MglobalFull), -Qglobal) # Record position of all grid points in global FoR at initial time step. DynOut[0:NumNodes_tot.value,:] = PosDefor # Record state of the selected node in initial deformed configuration. PosPsiTime[0,:3] = PosDefor[-1,:] PosPsiTime[0,3:] = PsiDefor[-1,XBELEM.NumNodes[-1]-1,:] # Get gamma and beta for Newmark scheme. gamma = 0.5 + XBOPTS.NewmarkDamp.value beta = 0.25*pow((gamma + 0.5),2) # Initialize Aero Section = InitSection(VMOPTS,VMINPUT,AELAOPTS.ElasticAxis) # Declare memory for Aero variables. ZetaDot = np.zeros((Section.shape[0],PosDefor.shape[0],3),ct.c_double,'C') K = VMOPTS.M.value*VMOPTS.N.value AIC = np.zeros((K,K),ct.c_double,'C') BIC = np.zeros((K,K),ct.c_double,'C') AeroForces = np.zeros((VMOPTS.M.value+1,VMOPTS.N.value+1,3),ct.c_double,'C') # Initialise A-frame location and orientation to be zero OriginA_G = np.zeros(3,ct.c_double,'C') PsiA_G = np.zeros(3,ct.c_double,'C') # Init external velocities. Ufree = InitSteadyExternalVels(VMOPTS,VMINPUT) # Init uninit vars if an impulsive start is specified. if AELAOPTS.ImpStart == True: Zeta = np.zeros((Section.shape[0],PosDefor.shape[0],3),ct.c_double,'C') Gamma = np.zeros((VMOPTS.M.value,VMOPTS.N.value),ct.c_double,'C') # Generate surface, wake and gamma matrices. CoincidentGrid(PosDefor, PsiDefor, Section, ForcedVel[0,:3], ForcedVel[0,3:], PosDotDef, PsiDotDef, XBINPUT, Zeta, ZetaDot, OriginA_G, PsiA_G, VMINPUT.ctrlSurf) # init wake grid and gamma matrix. ZetaStar, GammaStar = InitSteadyWake(VMOPTS,VMINPUT,Zeta,ForcedVel[0,:3]) # Init GammaDot GammaDot = np.zeros_like(Gamma, ct.c_double, 'C') # Define tecplot stuff if Settings.PlotTec==True: FileName = Settings.OutputDir + Settings.OutputFileRoot + 'AeroGrid.dat' Variables = ['X', 'Y', 'Z','Gamma'] FileObject = PostProcess.WriteAeroTecHeader(FileName, 'Default', Variables) # Plot results of static analysis PostProcess.WriteUVLMtoTec(FileObject, Zeta, ZetaStar, Gamma, GammaStar, TimeStep = 0, NumTimeSteps = XBOPTS.NumLoadSteps.value, Time = 0.0, Text = False) # Open output file for writing if 'writeDict' in kwords and Settings.WriteOut == True: fp = OpenOutFile(kwords['writeDict'], XBOPTS, Settings) # Write initial outputs to file. if 'writeDict' in kwords and Settings.WriteOut == True: WriteToOutFile(kwords['writeDict'], fp, Time[0], PosDefor, PsiDefor, PosIni, PsiIni, XBELEM, ctrlSurf, kwords['mpcCont']) # END if write # Time loop. for iStep in range(NumSteps.value): if XBOPTS.PrintInfo.value==True: sys.stdout.write('Time: %-10.4e\n' %(Time[iStep+1])) sys.stdout.write(' SubIter DeltaF DeltaX ResLog10\n') dt = Time[iStep+1] - Time[iStep] # Set dt for aero force calcs. VMOPTS.DelTime = ct.c_double(dt) # Save Gamma at iStep. GammaSav = Gamma.copy(order = 'C') # Force at current time-step if iStep > 0 and AELAOPTS.Tight == False: # zero aero forces. AeroForces[:,:,:] = 0.0 # Update CRV. PsiA_G = xbl.quat2psi(Quat) # CRV at iStep # Update origin. OriginA_G[:] = OriginA_G[:] + ForcedVel[iStep-1,:3]*dt # Update control surface deflection. if VMINPUT.ctrlSurf != None: if 'mpcCont' in kwords and kwords['mpcCont'] != None: uOpt = kwords['mpcCont'].getUopt( getState(Gamma,GammaStar,GammaDot,X,dXdt) ) VMINPUT.ctrlSurf.update(Time[iStep],uOpt[0,0]) else: VMINPUT.ctrlSurf.update(Time[iStep]) # Generate surface grid. CoincidentGrid(PosDefor, PsiDefor, Section, ForcedVel[iStep,:3], ForcedVel[iStep,3:], PosDotDef, PsiDotDef, XBINPUT, Zeta, ZetaDot, OriginA_G, PsiA_G, VMINPUT.ctrlSurf) # Update wake geom #'roll' data. ZetaStar = np.roll(ZetaStar,1,axis = 0) GammaStar = np.roll(GammaStar,1,axis = 0) #overwrite grid points with TE. ZetaStar[0,:] = Zeta[VMOPTS.M.value,:] # overwrite Gamma with TE value from previous timestep. GammaStar[0,:] = Gamma[VMOPTS.M.value-1,:] # Apply gust velocity. if VMINPUT.gust != None: Utot = Ufree + VMINPUT.gust.Vels(Zeta) else: Utot = Ufree # Solve for AeroForces. UVLMLib.Cpp_Solver_VLM(Zeta, ZetaDot, Utot, ZetaStar, VMOPTS, AeroForces, Gamma, GammaStar, AIC, BIC) # Get GammaDot. GammaDot[:] = Gamma[:] - GammaSav[:] # Apply density scaling. AeroForces[:,:,:] = AELAOPTS.AirDensity*AeroForces[:,:,:] if Settings.PlotTec==True: PostProcess.WriteUVLMtoTec(FileObject, Zeta - OriginA_G[:], ZetaStar - OriginA_G[:], Gamma, GammaStar, TimeStep = iStep, NumTimeSteps = XBOPTS.NumLoadSteps.value, Time = Time[iStep], Text = False) # map AeroForces to beam. CoincidentGridForce(XBINPUT, PsiDefor, Section, AeroForces, Force) # Add gravity loads. AddGravityLoads(Force, XBINPUT, XBELEM, AELAOPTS, PsiDefor, VMINPUT.c) #END if iStep > 0 # Quaternion update for orientation. Temp = np.linalg.inv(Unit4 + 0.25*xbl.QuadSkew(ForcedVel[iStep+1,3:])*dt) Quat = np.dot(Temp, np.dot(Unit4 - 0.25*xbl.QuadSkew(ForcedVel[iStep,3:])*dt, Quat)) Quat = Quat/np.linalg.norm(Quat) Cao = xbl.Rot(Quat) # transformation matrix at iStep+1 if AELAOPTS.Tight == True: # CRV at iStep+1 PsiA_G = xbl.quat2psi(Quat) # Origin at iStep+1 OriginA_G[:] = OriginA_G[:] + ForcedVel[iStep,:3]*dt GammaSav = Gamma.copy(order = 'C') # Predictor step. X = X + dt*dXdt + (0.5-beta)*dXddt*pow(dt,2.0) dXdt = dXdt + (1.0-gamma)*dXddt*dt dXddt[:] = 0.0 # Reset convergence parameters. Iter = 0 ResLog10 = 0.0 # Newton-Raphson loop. while ( (ResLog10 > np.log10(XBOPTS.MinDelta.value)) & (Iter < XBOPTS.MaxIterations.value) ): # set tensors to zero. Qglobal[:] = 0.0 Mvel[:,:] = 0.0 Cvel[:,:] = 0.0 MglobalFull[:,:] = 0.0 CglobalFull[:,:] = 0.0 KglobalFull[:,:] = 0.0 FglobalFull[:,:] = 0.0 # Update counter. Iter += 1 if XBOPTS.PrintInfo.value==True: sys.stdout.write(' %-7d ' %(Iter)) # nodal diplacements and velocities from state vector. BeamLib.Cbeam3_Solv_State2Disp(XBINPUT, NumNodes_tot, XBELEM, XBNODE, PosIni, PsiIni, NumDof, X, dXdt, PosDefor, PsiDefor, PosDotDef, PsiDotDef) # if tightly coupled is on then get new aeroforces. if AELAOPTS.Tight == True: # zero aero forces. AeroForces[:,:,:] = 0.0 # Set gamma at t-1 to saved solution. Gamma[:,:] = GammaSav[:,:] # get new grid. # The rigid-body DoFs (OriginA_G,PsiA_G,ForcedVel) at time step # i+1 are used to converge the aeroelastic equations. CoincidentGrid(PosDefor, PsiDefor, Section, ForcedVel[iStep+1,:3], ForcedVel[iStep+1,3:], PosDotDef, PsiDotDef, XBINPUT, Zeta, ZetaDot, OriginA_G, PsiA_G, VMINPUT.ctrlSurf) # close wake. ZetaStar[0,:] = Zeta[VMOPTS.M.value,:] # save pereference and turn off rollup. Rollup = VMOPTS.Rollup.value VMOPTS.Rollup.value = False # Solve for AeroForces. UVLMLib.Cpp_Solver_VLM(Zeta, ZetaDot, Ufree, ZetaStar, VMOPTS, AeroForces, Gamma, GammaStar, AIC, BIC) # turn rollup back to original preference VMOPTS.Rollup.value = Rollup # apply density scaling. AeroForces[:,:,:] = AELAOPTS.AirDensity*AeroForces[:,:,:] # beam forces. CoincidentGridForce(XBINPUT, PsiDefor, Section, AeroForces, Force) # Add gravity loads. AddGravityLoads(Force,XBINPUT,XBELEM,AELAOPTS, PsiDefor,VMINPUT.c) #END if Tight ForcedVelLoc = ForcedVel[iStep+1,:].copy('F') ForcedVelDotLoc = ForcedVelDot[iStep+1,:].copy('F') # Update matrices. BeamLib.Cbeam3_Asbly_Dynamic(XBINPUT, NumNodes_tot, XBELEM, XBNODE, PosIni, PsiIni, PosDefor, PsiDefor, PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef, Force, ForcedVelLoc, ForcedVelDotLoc, NumDof, Settings.DimMat, ms, MglobalFull, Mvel, cs, CglobalFull, Cvel, ks, KglobalFull, fs, FglobalFull, Qglobal, XBOPTS, Cao) # Get force vector for unconstrained nodes (Force_Dof). BeamLib.f_fem_m2v(ct.byref(NumNodes_tot), ct.byref(ct.c_int(6)), Force.ctypes.data_as(ct.POINTER(ct.c_double)), ct.byref(NumDof), Force_Dof.ctypes.data_as(ct.POINTER(ct.c_double)), XBNODE.Vdof.ctypes.data_as(ct.POINTER(ct.c_int)) ) # Solve for update vector. # Residual. Qglobal = Qglobal + np.dot(MglobalFull, dXddt) \ + np.dot(Mvel,ForcedVelDotLoc) \ - np.dot(FglobalFull, Force_Dof) if XBOPTS.PrintInfo.value==True: sys.stdout.write('%-10.4e ' %(max(abs(Qglobal)))) # Calculate system matrix for update calculation. Asys = KglobalFull \ + CglobalFull*gamma/(beta*dt) \ + MglobalFull/(beta*pow(dt,2.0)) # Solve for update. DX[:] = np.dot(np.linalg.inv(Asys), -Qglobal) # Corrector step. X = X + DX dXdt = dXdt + DX*gamma/(beta*dt) dXddt = dXddt + DX/(beta*pow(dt,2.0)) # Residual at first iteration. if(Iter == 1): Res0_Qglobal = max(abs(Qglobal)) + 1.e-16 Res0_DeltaX = max(abs(DX)) + 1.e-16 # Update residual and compute log10. Res_Qglobal = max(abs(Qglobal)) + 1.e-16 Res_DeltaX = max(abs(DX)) + 1.e-16 ResLog10 = max([np.log10(Res_Qglobal/Res0_Qglobal), np.log10(Res_DeltaX/Res0_DeltaX)]) if XBOPTS.PrintInfo.value==True: sys.stdout.write('%-10.4e %8.4f\n' %(max(abs(DX)),ResLog10)) if ResLog10 > 2.0: print("Residual growing! Exit Newton-Raphson...") break # END Netwon-Raphson. if ResLog10 > 2.0: print("Residual growing! Exit time-loop...") debug = 'here' del debug break # Update to converged nodal displacements and velocities. BeamLib.Cbeam3_Solv_State2Disp(XBINPUT, NumNodes_tot, XBELEM, XBNODE, PosIni, PsiIni, NumDof, X, dXdt, PosDefor, PsiDefor, PosDotDef, PsiDotDef) PosPsiTime[iStep+1,:3] = PosDefor[-1,:] PosPsiTime[iStep+1,3:] = PsiDefor[-1,XBELEM.NumNodes[-1]-1,:] # Position of all grid points in global FoR. i1 = (iStep+1)*NumNodes_tot.value i2 = (iStep+2)*NumNodes_tot.value DynOut[i1:i2,:] = PosDefor # Write selected outputs if 'writeDict' in kwords and Settings.WriteOut == True: WriteToOutFile(writeDict, fp, Time[iStep+1], PosDefor, PsiDefor, PosIni, PsiIni, XBELEM, ctrlSurf, kwords['mpcCont']) # END if write. ZetaStar[:,:] = ZetaStar[:,:] + VMINPUT.U_infty*dt if VMINPUT.gust != None: ZetaStar[:,:,:] = ZetaStar[:,:,:] + VMINPUT.gust.Vels(ZetaStar)*dt # END Time loop # Write _dyn file. ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL312_dyn.dat' fp = open(ofile,'w') BeamIO.Write_dyn_File(fp, Time, PosPsiTime) fp.close() # "Write _shape file" # ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL312_shape.dat' # fp = open(ofile,'w') # BeamIO.Write_shape_File(fp, len(Time), NumNodes_tot.value, Time, DynOut) # fp.close() # Close output file if it exists. if 'writeDict' in kwords and Settings.WriteOut == True: fp.close() # Close Tecplot ascii FileObject. if Settings.PlotTec==True: PostProcess.CloseAeroTecFile(FileObject) if XBOPTS.PrintInfo.value==True: sys.stdout.write(' ... done\n') # For interactive analysis at end of simulation set breakpoint. pass
def Solve_Py(XBINPUT, XBOPTS, VMOPTS, VMINPUT, AELAOPTS): """Nonlinear static solver using Python to solve aeroelastic equation. Assembly of structural matrices is carried out with Fortran subroutines. Aerodynamics solved using PyAero.UVLM.""" assert XBOPTS.Solution.value == 112, "NonlinearStatic requested" + " with wrong solution code" # Initialize beam. XBINPUT, XBOPTS, NumNodes_tot, XBELEM, PosIni, PsiIni, XBNODE, NumDof = BeamInit.Static(XBINPUT, XBOPTS) # Set initial conditions as undef config. PosDefor = PosIni.copy(order="F") PsiDefor = PsiIni.copy(order="F") if XBOPTS.PrintInfo.value == True: sys.stdout.write("Solve nonlinear static case in Python ... \n") # Initialise structural eqn tensors. KglobalFull = np.zeros((NumDof.value, NumDof.value), ct.c_double, "F") ks = ct.c_int() FglobalFull = np.zeros((NumDof.value, NumDof.value), ct.c_double, "F") fs = ct.c_int() DeltaS = np.zeros(NumDof.value, ct.c_double, "F") Qglobal = np.zeros(NumDof.value, ct.c_double, "F") x = np.zeros(NumDof.value, ct.c_double, "F") dxdt = np.zeros(NumDof.value, ct.c_double, "F") # Beam Load Step tensors iForceStep = np.zeros((NumNodes_tot.value, 6), ct.c_double, "F") iForceStep_Dof = np.zeros(NumDof.value, ct.c_double, "F") # Initialze Aero. Section = InitSection(VMOPTS, VMINPUT, AELAOPTS.ElasticAxis) # Declare memory for Aero grid and velocities. Zeta = np.zeros((Section.shape[0], PosDefor.shape[0], 3), ct.c_double, "C") ZetaDot = np.zeros((Section.shape[0], PosDefor.shape[0], 3), ct.c_double, "C") # Additional Aero solver variables. AeroForces = np.zeros((VMOPTS.M.value + 1, VMOPTS.N.value + 1, 3), ct.c_double, "C") Gamma = np.zeros((VMOPTS.M.value, VMOPTS.N.value), ct.c_double, "C") # Init external velocities. Uext = InitSteadyExternalVels(VMOPTS, VMINPUT) # Create zero triads for motion of reference frame. VelA_A = np.zeros((3)) OmegaA_A = np.zeros((3)) # Create zero vectors for structural vars not used in static analysis. PosDotDef = np.zeros_like(PosDefor, ct.c_double, "F") PsiDotDef = np.zeros_like(PsiDefor, ct.c_double, "F") # Define tecplot stuff. FileName = Settings.OutputDir + Settings.OutputFileRoot + "AeroGrid.dat" Variables = ["X", "Y", "Z", "Gamma"] FileObject = PostProcess.WriteAeroTecHeader(FileName, "Default", Variables) # Start Load Loop. for iLoadStep in range(XBOPTS.NumLoadSteps.value): # Reset convergence parameters and loads. Iter = 0 ResLog10 = 0.0 XBINPUT.ForceStatic[:, :] = 0.0 AeroForces[:, :, :] = 0.0 # Calculate aero loads. if hasattr(XBINPUT, "ForcedVel"): CoincidentGrid( PosDefor, PsiDefor, Section, XBINPUT.ForcedVel[0, :3], XBINPUT.ForcedVel[0, 3:], PosDotDef, PsiDotDef, XBINPUT, Zeta, ZetaDot, ctrlSurf=VMINPUT.ctrlSurf, ) else: CoincidentGrid( PosDefor, PsiDefor, Section, VelA_A, OmegaA_A, PosDotDef, PsiDotDef, XBINPUT, Zeta, ZetaDot, ctrlSurf=VMINPUT.ctrlSurf, ) if hasattr(XBINPUT, "ForcedVel"): ZetaStar, GammaStar = InitSteadyWake(VMOPTS, VMINPUT, Zeta, XBINPUT.ForcedVel[0, :3]) else: ZetaStar, GammaStar = InitSteadyWake(VMOPTS, VMINPUT, Zeta) # Solve for AeroForces. UVLMLib.Cpp_Solver_VLM(Zeta, ZetaDot, Uext, ZetaStar, VMOPTS, AeroForces, Gamma, GammaStar) AeroForces[:, :, :] = AELAOPTS.AirDensity * AeroForces[:, :, :] # Write solution to tecplot file. PostProcess.WriteUVLMtoTec( FileObject, Zeta, ZetaStar, Gamma, GammaStar, iLoadStep, XBOPTS.NumLoadSteps.value, iLoadStep * 1.0, Text=True, ) # Map AeroForces to beam. CoincidentGridForce(XBINPUT, PsiDefor, Section, AeroForces, XBINPUT.ForceStatic) # Add gravity loads. AddGravityLoads(XBINPUT.ForceStatic, XBINPUT, XBELEM, AELAOPTS, PsiDefor, VMINPUT.c) # Apply factor corresponding to force step. iForceStep = XBINPUT.ForceStatic * float((iLoadStep + 1)) / XBOPTS.NumLoadSteps.value if XBOPTS.PrintInfo.value == True: sys.stdout.write(" iLoad: %-10d\n" % (iLoadStep + 1)) sys.stdout.write(" SubIter DeltaF DeltaX ResLog10\n") # Start Newton Iteration. while (ResLog10 > np.log10(XBOPTS.MinDelta.value)) & (Iter < XBOPTS.MaxIterations.value): Iter += 1 if XBOPTS.PrintInfo.value == True: sys.stdout.write(" %-7d " % (Iter)) # Set structural eqn tensors to zero KglobalFull[:, :] = 0.0 ks = ct.c_int() FglobalFull[:, :] = 0.0 fs = ct.c_int() Qglobal[:] = 0.0 # Assemble matrices for static problem BeamLib.Cbeam3_Asbly_Static( XBINPUT, NumNodes_tot, XBELEM, XBNODE, PosIni, PsiIni, PosDefor, PsiDefor, iForceStep, NumDof, ks, KglobalFull, fs, FglobalFull, Qglobal, XBOPTS, ) # Get state vector from current deformation. PosDot = np.zeros((NumNodes_tot.value, 3), ct.c_double, "F") PsiDot = np.zeros((XBINPUT.NumElems, Settings.MaxElNod, 3), ct.c_double, "F") BeamLib.Cbeam_Solv_Disp2State( NumNodes_tot, NumDof, XBINPUT, XBNODE, PosDefor, PsiDefor, PosDot, PsiDot, x, dxdt ) # Get forces on unconstrained nodes. BeamLib.f_fem_m2v( ct.byref(NumNodes_tot), ct.byref(ct.c_int(6)), iForceStep.ctypes.data_as(ct.POINTER(ct.c_double)), ct.byref(NumDof), iForceStep_Dof.ctypes.data_as(ct.POINTER(ct.c_double)), XBNODE.Vdof.ctypes.data_as(ct.POINTER(ct.c_int)), ) # Calculate \Delta RHS. Qglobal = Qglobal - np.dot(FglobalFull, iForceStep_Dof) # Calculate \Delta State Vector. DeltaS = -np.dot(np.linalg.inv(KglobalFull), Qglobal) if XBOPTS.PrintInfo.value == True: sys.stdout.write("%-10.4e %-10.4e " % (max(abs(Qglobal)), max(abs(DeltaS)))) # Update Solution. BeamLib.Cbeam3_Solv_Update_Static( XBINPUT, NumNodes_tot, XBELEM, XBNODE, NumDof, DeltaS, PosIni, PsiIni, PosDefor, PsiDefor ) # Record residual at first iteration. if Iter == 1: Res0_Qglobal = max(abs(Qglobal)) + 1.0e-16 Res0_DeltaX = max(abs(DeltaS)) + 1.0e-16 # Update residual and compute log10 Res_Qglobal = max(abs(Qglobal)) + 1.0e-16 Res_DeltaX = max(abs(DeltaS)) + 1.0e-16 ResLog10 = max([np.log10(Res_Qglobal / Res0_Qglobal), np.log10(Res_DeltaX / Res0_DeltaX)]) if XBOPTS.PrintInfo.value == True: sys.stdout.write("%8.4f\n" % (ResLog10)) # Stop the solution. if ResLog10 > 10.0: sys.stderr.write(" STOP\n") sys.stderr.write(" The max residual is %e\n" % (ResLog10)) exit(1) elif Res_DeltaX < 1.0e-14: break # END Newton iteration # END Load step loop if XBOPTS.PrintInfo.value == True: sys.stdout.write(" ... done\n") # Write deformed configuration to file. ofile = Settings.OutputDir + Settings.OutputFileRoot + "_SOL112_def.dat" if XBOPTS.PrintInfo.value == True: sys.stdout.write("Writing file %s ... " % (ofile)) fp = open(ofile, "w") fp.write('TITLE="Non-linear static solution: deformed geometry"\n') fp.write('VARIABLES="iElem" "iNode" "Px" "Py" "Pz" "Rx" "Ry" "Rz"\n') fp.close() if XBOPTS.PrintInfo.value == True: sys.stdout.write("done\n") WriteMode = "a" BeamIO.OutputElems(XBINPUT.NumElems, NumNodes_tot.value, XBELEM, PosDefor, PsiDefor, ofile, WriteMode) # Print deformed configuration. if XBOPTS.PrintInfo.value == True: sys.stdout.write("--------------------------------------\n") sys.stdout.write("NONLINEAR STATIC SOLUTION\n") sys.stdout.write("%10s %10s %10s\n" % ("X", "Y", "Z")) for inodi in range(NumNodes_tot.value): sys.stdout.write(" ") for inodj in range(3): sys.stdout.write("%12.5e" % (PosDefor[inodi, inodj])) sys.stdout.write("\n") sys.stdout.write("--------------------------------------\n") # Close Tecplot ascii FileObject. PostProcess.CloseAeroTecFile(FileObject) # Return solution return PosDefor, PsiDefor, Zeta, ZetaStar, Gamma, GammaStar, iForceStep
def Solve_Py(XBINPUT,XBOPTS,SaveDict=Settings.SaveDict): """Nonlinear dynamic structural solver in Python. Assembly of matrices is carried out with Fortran subroutines.""" #Check correct solution code assert XBOPTS.Solution.value == 912, ('NonlinearDynamic requested' +\ ' with wrong solution code') # I/O management Settings.SaveDict=SaveDict # overwrite for compatibility with 'dat' format output XBOUT=DerivedTypes.Xboutput() XBOUT.cputime.append(time.clock()) if SaveDict['Format']=='h5': Settings.WriteOut=False Settings.PlotTec=False OutList=[XBOPTS, XBINPUT, XBOUT] #Initialise beam XBINPUT, XBOPTS, NumNodes_tot, XBELEM, PosIni, PsiIni, XBNODE, NumDof \ = BeamInit.Static(XBINPUT,XBOPTS) # Solve static # Note: gravity loads added according to XBINPUT.PsiA_G into Solve_Py_Static if XBOPTS.ImpStart==True: PosDefor = PosIni.copy(order='F') PsiDefor = PsiIni.copy(order='F') XBOUT.ForceStaticTotal = XBINPUT.ForceStatic.copy('F') AddGravityLoads(XBOUT.ForceStaticTotal,XBINPUT,XBELEM, AELAOPTS=None, # allows defining inertial/elastic axis PsiDefor=PsiDefor, chord=0.0, # used to define inertial/elastic axis PsiA_G=XBINPUT.PsiA_G, FollowerForceRig=XBOPTS.FollowerForceRig.value) else: if XBNODE.Sflag.any(): raise NameError('Static solution with spherical joint not ' 'implemented and/or possible!') XBOPTS.Solution.value = 112 XBSTA = Solve_Py_Static(XBINPUT, XBOPTS, SaveDict=SaveDict) XBOPTS.Solution.value = 912 PosDefor=XBSTA.PosDeforStatic.copy(order='F') PsiDefor=XBSTA.PsiDeforStatic.copy(order='F') XBOUT.PosDeforStatic =XBSTA.PosDeforStatic XBOUT.PsiDeforStatic =XBSTA.PsiDeforStatic XBOUT.ForceStaticTotal=XBSTA.ForceStaticTotal # includes gravity del XBSTA if SaveDict['Format']=='dat': PyLibs.io.dat.write_SOL912_def(XBOPTS,XBINPUT,XBELEM, NumNodes_tot,PosDefor,PsiDefor,SaveDict) ## sm I/O #XBOUT.PosDefor=PosDefor #XBOUT.PsiDefor=PsiDefor #Initialise variables for dynamic analysis Time, NumSteps, ForceTime, Vrel, VrelDot,\ PosDotDef, PsiDotDef,\ OutGrids, PosPsiTime, VelocTime, DynOut = BeamInit.Dynamic(XBINPUT,XBOPTS) # Delete unused variables. del OutGrids, VelocTime #Write _force file if SaveDict['Format']=='dat': PyLibs.io.dat.write_SOL912_force(XBOPTS,XBINPUT,XBELEM, Time, ForceTime, Vrel, VrelDot) # sm I/O ### why forced velocity with Sol912 ??? ### If forced velocities are prescribed, then is Sol312 XBOUT.Time_force=Time # ...SOL912_force.dat XBOUT.ForceTime_force=ForceTime XBOUT.Vrel_force=Vrel XBOUT.VrelDot_force=VrelDot # debugging XBOUT.KsysList=[] XBOUT.MsysList=[] #---------------------------------------------------- Start Dynamic Solution if XBOPTS.PrintInfo.value==True: sys.stdout.write('Solve nonlinear dynamic case in Python ... \n') #Initialise structural system tensors MssFull = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F') CssFull = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F') KssFull = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F') FstrucFull = np.zeros((NumDof.value,NumDof.value), ct.c_double, 'F') ms = ct.c_int() cs = ct.c_int() ks = ct.c_int() fs = ct.c_int() Msr = np.zeros((NumDof.value,6), ct.c_double, 'F') Csr = np.zeros((NumDof.value,6), ct.c_double, 'F') X = np.zeros(NumDof.value, ct.c_double, 'F') dXdt = np.zeros(NumDof.value, ct.c_double, 'F') Force_Dof = np.zeros(NumDof.value, ct.c_double, 'F') Qstruc = np.zeros(NumDof.value, ct.c_double, 'F') #Initialise rigid-body system tensors MrsFull = np.zeros((6,NumDof.value), ct.c_double, 'F') CrsFull = np.zeros((6,NumDof.value), ct.c_double, 'F') KrsFull = np.zeros((6,NumDof.value), ct.c_double, 'F') FrigidFull = np.zeros((6,NumDof.value+6), ct.c_double, 'F') mr = ct.c_int() cr = ct.c_int() kr = ct.c_int() fr = ct.c_int() Mrr = np.zeros((6,6), ct.c_double, 'F') Crr = np.zeros((6,6), ct.c_double, 'F') Qrigid = np.zeros(6, ct.c_double, 'F') #Initialise full system tensors Q = np.zeros(NumDof.value+6+4, ct.c_double, 'F') DQ = np.zeros(NumDof.value+6+4, ct.c_double, 'F') dQdt = np.zeros(NumDof.value+6+4, ct.c_double, 'F') dQddt = np.zeros(NumDof.value+6+4, ct.c_double, 'F') Force_All = np.zeros(NumDof.value+6, ct.c_double, 'F') Msys = np.zeros((NumDof.value+6+4,NumDof.value+6+4), ct.c_double, 'F') Csys = np.zeros((NumDof.value+6+4,NumDof.value+6+4), ct.c_double, 'F') Ksys = np.zeros((NumDof.value+6+4,NumDof.value+6+4), ct.c_double, 'F') Asys = np.zeros((NumDof.value+6+4,NumDof.value+6+4), ct.c_double, 'F') Qsys = np.zeros(NumDof.value+6+4, ct.c_double, 'F') #Initialise rotation operators Quat = xbl.psi2quat(XBINPUT.PsiA_G) Cao = XbeamLib.Rot(Quat) ACoa = np.zeros((6,6), ct.c_double, 'F') Cqr = np.zeros((4,6), ct.c_double, 'F') Cqq = np.zeros((4,4), ct.c_double, 'F') Unit4 = np.zeros((4,4), ct.c_double, 'F') for i in range(4): Unit4[i,i] = 1.0 #Extract initial displacements and velocities BeamLib.Cbeam_Solv_Disp2State(NumNodes_tot, NumDof, XBINPUT, XBNODE, PosDefor, PsiDefor, PosDotDef, PsiDotDef, X, dXdt) #Initialise accelerations as zero arrays PosDotDotDef = np.zeros((NumNodes_tot.value,3),ct.c_double,'F') PsiDotDotDef = np.zeros((XBINPUT.NumElems,Settings.MaxElNod,3), ct.c_double, 'F') #Populate state vector Q[:NumDof.value]=X.copy('F') dQdt[:NumDof.value]=dXdt.copy('F') dQdt[NumDof.value:NumDof.value+6] = Vrel[0,:].copy('F') dQdt[NumDof.value+6:]= Quat.copy('F') # Force at the first time-step # Gravity needs including for correctly computing the accelerations at the # 1st time-step # Note: rank of Force increased after removing ForceTime #Force = (XBINPUT.ForceStatic + XBINPUT.ForceDyn*ForceTime[0]).copy('F') #Force = (XBINPUT.ForceStatic + XBINPUT.ForceDyn[0,:,:]).copy('F') Force = (XBOUT.ForceStaticTotal + XBINPUT.ForceDyn[0,:,:]).copy('F') #Assemble matrices and loads for structural dynamic analysis tmpVrel=Vrel[0,:].copy('F') tmpQuat=Quat.copy('F') BeamLib.Cbeam3_Asbly_Dynamic(XBINPUT, NumNodes_tot, XBELEM, XBNODE, PosIni, PsiIni, PosDefor, PsiDefor, PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef, Force, tmpVrel, 0*tmpVrel, NumDof, Settings.DimMat, ms, MssFull, Msr, cs, CssFull, Csr, ks, KssFull, fs, FstrucFull, Qstruc, XBOPTS, Cao) BeamLib.f_fem_m2v(ct.byref(NumNodes_tot),\ ct.byref(ct.c_int(6)),\ Force.ctypes.data_as(ct.POINTER(ct.c_double)),\ ct.byref(NumDof),\ Force_Dof.ctypes.data_as(ct.POINTER(ct.c_double)),\ XBNODE.Vdof.ctypes.data_as(ct.POINTER(ct.c_int)) ) Qstruc -= np.dot(FstrucFull, Force_Dof) #Assemble matrices for rigid-body dynamic analysis BeamLib.Xbeam_Asbly_Dynamic(XBINPUT, NumNodes_tot, XBELEM, XBNODE,\ PosIni, PsiIni, PosDefor, PsiDefor,\ PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef,\ tmpVrel, 0*tmpVrel, tmpQuat,\ NumDof, Settings.DimMat,\ mr, MrsFull, Mrr,\ cr, CrsFull, Crr, Cqr, Cqq,\ kr, KrsFull, fr, FrigidFull,\ Qrigid, XBOPTS, Cao) BeamLib.f_fem_m2v_nofilter(ct.byref(NumNodes_tot),\ ct.byref(ct.c_int(6)),\ Force.ctypes.data_as(ct.POINTER(ct.c_double)),\ ct.byref(ct.c_int(NumDof.value+6)),\ Force_All.ctypes.data_as(ct.POINTER(ct.c_double)) ) Qrigid -= np.dot(FrigidFull, Force_All) #Separate assembly of follower and dead loads tmpForceTime=ForceTime[0].copy('F') tmpQforces,Dummy,tmpQrigid = XbeamLib.LoadAssembly(XBINPUT, XBELEM, XBNODE, XBOPTS, NumDof, \ PosIni, PsiIni, PosDefor, PsiDefor, \ ### sm increased rank of ForceDyn_* #(XBINPUT.ForceStatic_foll + XBINPUT.ForceDyn_foll*tmpForceTime), \ #(XBINPUT.ForceStatic_dead + XBINPUT.ForceDyn_dead*tmpForceTime), \ (XBINPUT.ForceStatic_foll + XBINPUT.ForceDyn_foll[0,:,:]), \ (XBINPUT.ForceStatic_dead + XBINPUT.ForceDyn_dead[0,:,:]), \ Cao,1) Qstruc -= tmpQforces Qrigid -= tmpQrigid #Assemble system matrices Msys[:NumDof.value,:NumDof.value] = MssFull.copy('F') Msys[:NumDof.value,NumDof.value:NumDof.value+6] = Msr.copy('F') Msys[NumDof.value:NumDof.value+6,:NumDof.value] = MrsFull.copy('F') Msys[NumDof.value:NumDof.value+6,NumDof.value:NumDof.value+6] = Mrr.copy('F') Msys[NumDof.value+6:,NumDof.value+6:] = Unit4.copy('F') Qsys[:NumDof.value] = Qstruc Qsys[NumDof.value:NumDof.value+6] = Qrigid Qsys[NumDof.value+6:] = np.dot(Cqq,dQdt[NumDof.value+6:]) # ------------------------------------------------------------------- # special BCs iiblock=[] if XBNODE.Sflag.any(): # block translations (redundant:) for ii in range(3): if XBINPUT.EnforceTraVel_FoRA[ii] == True: iiblock.append(NumDof.value+ii) # block rotations iirotfree=[] # free rotational dof for ii in range(3): if XBINPUT.EnforceAngVel_FoRA[ii] is True: iiblock.append(NumDof.value+3+ii) else: iirotfree.append(NumDof.value+3+ii) if len(iiblock)>0: Msys[iiblock,:] = 0.0 Msys[:,iiblock] = 0.0 Msys[iiblock,iiblock] = 1.0 Csys[iiblock,:] = 0.0 Ksys[iiblock,:] = 0.0 Qsys[iiblock] = 0.0 if XBINPUT.sph_joint_damping is not None: Csys[iirotfree,iirotfree] += XBINPUT.sph_joint_damping Qsys[iirotfree] += XBINPUT.sph_joint_damping*dQdt[iirotfree] #from IPython import embed; embed() # add structural damping term if XBINPUT.str_damping_model is not None: Cdamp = XBINPUT.str_damping_param['alpha'] * MssFull + \ XBINPUT.str_damping_param['beta'] * KssFull Qsys[:NumDof.value] += np.dot( Cdamp, dQdt[:NumDof.value] ) pass # ------------------------------------------------------------------- #store initial matrices for eigenvalues analysis XBOUT.Msys0 = Msys.copy() XBOUT.Csys0 = Csys.copy() XBOUT.Ksys0 = Ksys.copy() XBOUT.Qsys0 = Qsys.copy() #Initial Accel #dQddt[:] = np.dot(np.linalg.inv(Msys), -Qsys) #dQddt[:] = np.linalg.solve(Msys,-Qsys) # most correct but inaccurate / Msys ill-conditioned # solve only rigid body dynamics dQddt[:NumDof.value]=0.0 dQddt[NumDof.value:]=np.linalg.solve( Msys[NumDof.value:,NumDof.value:], -Qsys[NumDof.value:] ) XBOUT.dQddt0=dQddt.copy() #Record position of all grid points in global FoR at initial time step DynOut[0:NumNodes_tot.value,:] = PosDefor #Position/rotation of the selected node in initial deformed configuration PosPsiTime[0,:3] = PosDefor[-1,:] PosPsiTime[0,3:] = PsiDefor[-1,XBELEM.NumNodes[-1]-1,:] #Get gamma and beta for Newmark scheme gamma = 0.5 + XBOPTS.NewmarkDamp.value beta = 0.25*(gamma + 0.5)**2 # sm write class XBOUT.QuatList.append(Quat) XBOUT.PosIni=PosIni XBOUT.PsiIni=PsiIni XBOUT.AsysListStart=[] XBOUT.AsysListEnd=[] XBOUT.MsysList=[] XBOUT.CsysList=[] XBOUT.KsysList=[] #Time loop for iStep in range(NumSteps.value): if XBOPTS.PrintInfo.value==True: sys.stdout.write(' Time: %-10.4e\n' %(Time[iStep+1])) sys.stdout.write(' SubIter DeltaF DeltaX ResLog10\n') #calculate dt dt = Time[iStep+1] - Time[iStep] ###Predictor step Q += dt*dQdt + (0.5-beta)*dQddt*dt**2 dQdt += (1.0-gamma)*dQddt*dt ### Corrector #dQddt[:] = 0.0 # initial guess for acceleration at next time-step is zero Q += beta*dQddt*dt**2 dQdt += gamma*dQddt*dt #Reset convergence parameters Iter = 0 ResLog10 = 1.0 #Newton-Raphson loop while ( (ResLog10 > XBOPTS.MinDelta.value) \ & (Iter < XBOPTS.MaxIterations.value) ): #set tensors to zero MssFull[:,:] = 0.0; CssFull[:,:] = 0.0 KssFull[:,:] = 0.0; FstrucFull[:,:] = 0.0 Msr[:,:] = 0.0; Csr[:,:] = 0.0 Qstruc[:] = 0.0 MrsFull[:,:] = 0.0; CrsFull[:,:] = 0.0 KrsFull[:,:] = 0.0; FrigidFull[:,:] = 0.0 Mrr[:,:] = 0.0; Crr[:,:] = 0.0 Qrigid[:] = 0.0 Msys[:,:] = 0.0; Csys[:,:] = 0.0 Ksys[:,:] = 0.0; Asys[:,:] = 0.0; Qsys[:] = 0.0 #Update counter Iter += 1 if XBOPTS.PrintInfo.value==True: sys.stdout.write(' %-7d ' %(Iter)) #nodal displacements and velocities from state vector X=Q[:NumDof.value].copy('F') dXdt=dQdt[:NumDof.value].copy('F'); BeamLib.Cbeam3_Solv_State2Disp(XBINPUT, NumNodes_tot, XBELEM, XBNODE, PosIni, PsiIni, NumDof, X, dXdt,\ PosDefor, PsiDefor, PosDotDef, PsiDotDef) #rigid-body velocities and orientation from state vector Vrel[iStep+1,:] = dQdt[NumDof.value:NumDof.value+6].copy('F') VrelDot[iStep+1,:] = dQddt[NumDof.value:NumDof.value+6].copy('F') Quat = dQdt[NumDof.value+6:].copy('F') Quat = Quat/np.linalg.norm(Quat) Cao = XbeamLib.Rot(Quat) ### sm: removed ForceTime and increased rank of ForceDyn # Note: do not add gravity load here! #Force at current time-step #Force = (XBINPUT.ForceStatic+XBINPUT.ForceDyn*ForceTime[iStep+1]).copy('F') Force = (XBINPUT.ForceStatic+XBINPUT.ForceDyn[iStep+1,:,:]).copy('F') # Add gravity loads (accounting for new orientation) AddGravityLoads(Force, XBINPUT, XBELEM, AELAOPTS=None, # allows defining inertial/elastic axis PsiDefor=PsiDefor, chord = 0.0, # used to define inertial/elastic axis PsiA_G=xbl.quat2psi(Quat), FollowerForceRig=XBOPTS.FollowerForceRig.value) #Assemble matrices and loads for structural dynamic analysis tmpVrel=Vrel[iStep+1,:].copy('F') tmpQuat=Quat.copy('F') BeamLib.Cbeam3_Asbly_Dynamic(XBINPUT, NumNodes_tot, XBELEM, XBNODE,\ PosIni, PsiIni, PosDefor, PsiDefor,\ PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef,\ Force, tmpVrel, 0*tmpVrel,\ NumDof, Settings.DimMat,\ ms, MssFull, Msr,\ cs, CssFull, Csr,\ ks, KssFull, fs, FstrucFull,\ Qstruc, XBOPTS, Cao) BeamLib.f_fem_m2v(ct.byref(NumNodes_tot),\ ct.byref(ct.c_int(6)),\ Force.ctypes.data_as(ct.POINTER(ct.c_double)),\ ct.byref(NumDof),\ Force_Dof.ctypes.data_as(ct.POINTER(ct.c_double)),\ XBNODE.Vdof.ctypes.data_as(ct.POINTER(ct.c_int)) ) #Assemble matrices for rigid-body dynamic analysis BeamLib.Xbeam_Asbly_Dynamic(XBINPUT, NumNodes_tot, XBELEM, XBNODE,\ PosIni, PsiIni, PosDefor, PsiDefor,\ PosDotDef, PsiDotDef, PosDotDotDef, PsiDotDotDef,\ tmpVrel, 0*tmpVrel, tmpQuat,\ NumDof, Settings.DimMat,\ mr, MrsFull, Mrr,\ cr, CrsFull, Crr, Cqr, Cqq,\ kr, KrsFull, fs, FrigidFull,\ Qrigid, XBOPTS, Cao) BeamLib.f_fem_m2v_nofilter(ct.byref(NumNodes_tot),\ ct.byref(ct.c_int(6)),\ Force.ctypes.data_as(ct.POINTER(ct.c_double)),\ ct.byref(ct.c_int(NumDof.value+6)),\ Force_All.ctypes.data_as(ct.POINTER(ct.c_double)) ) #Residual at first iteration if(Iter == 1): Res0_Qglobal = max(max(abs(Qsys)),1) Res0_DeltaX = max(max(abs(DQ)),1) #Assemble discrete system matrices with linearised quaternion equations Msys[:NumDof.value,:NumDof.value] = MssFull.copy('F') Msys[:NumDof.value,NumDof.value:NumDof.value+6] = Msr.copy('F') Msys[NumDof.value:NumDof.value+6,:NumDof.value] = MrsFull.copy('F') Msys[NumDof.value:NumDof.value+6,NumDof.value:NumDof.value+6] = Mrr.copy('F') Msys[NumDof.value+6:,NumDof.value+6:] = Unit4.copy('F') Csys[:NumDof.value,:NumDof.value] = CssFull.copy('F') Csys[:NumDof.value,NumDof.value:NumDof.value+6] = Csr.copy('F') Csys[NumDof.value:NumDof.value+6,:NumDof.value] = CrsFull.copy('F') Csys[NumDof.value:NumDof.value+6,NumDof.value:NumDof.value+6] = Crr.copy('F') Csys[NumDof.value+6:,NumDof.value:NumDof.value+6] = Cqr.copy('F') Csys[NumDof.value+6:,NumDof.value+6:] = Cqq.copy('F') Ksys[:NumDof.value,:NumDof.value] = KssFull.copy('F') Ksys[NumDof.value:NumDof.value+6,:NumDof.value] = KrsFull.copy('F') #Separate assembly of follower and dead loads #tmpForceTime=ForceTime[iStep+1].copy('F') tmpQforces,Dummy,tmpQrigid = XbeamLib.LoadAssembly(XBINPUT, XBELEM, XBNODE, XBOPTS, NumDof, \ PosIni, PsiIni, PosDefor, PsiDefor, \ ### sm: increased rank of ForceDyn_* #(XBINPUT.ForceStatic_foll + XBINPUT.ForceDyn_foll*tmpForceTime), \ #(XBINPUT.ForceStatic_dead + XBINPUT.ForceDyn_dead*tmpForceTime), \ (XBINPUT.ForceStatic_foll + XBINPUT.ForceDyn_foll[iStep+1,:,:] ), \ (XBINPUT.ForceStatic_dead + XBINPUT.ForceDyn_dead[iStep+1,:,:] ), \ Cao,1) Qstruc -= tmpQforces Qrigid -= tmpQrigid #Compute residual Qstruc += -np.dot(FstrucFull, Force_Dof) Qrigid += -np.dot(FrigidFull, Force_All) # final of last iter XBOUT.Qstruc=Qstruc.copy() XBOUT.Qrigid=Qrigid.copy() # final of initial iter if iStep==0: XBOUT.Qstruc0=Qstruc.copy() XBOUT.Qrigid0=Qrigid.copy() Qsys[:NumDof.value] = Qstruc Qsys[NumDof.value:NumDof.value+6] = Qrigid Qsys[NumDof.value+6:] = np.dot(Cqq,dQdt[NumDof.value+6:]) Qsys += np.dot(Msys,dQddt) # include damping if XBINPUT.str_damping_model == 'prop': Cdamp = XBINPUT.str_damping_param['alpha'] * MssFull + \ XBINPUT.str_damping_param['beta'] * KssFull Csys[:NumDof.value,:NumDof.value] += Cdamp Qsys[:NumDof.value] += np.dot(Cdamp, dQdt[:NumDof.value]) # special BCs # if SphFlag: if len(iiblock)>0: # allow to enforce only attitude while keeping velocity free Msys[iiblock,:] = 0.0 Msys[iiblock,iiblock] = 1.0 Csys[iiblock,:] = 0.0 Ksys[iiblock,:] = 0.0 Qsys[iiblock] = 0.0 if XBINPUT.sph_joint_damping is not None: Csys[iirotfree,iirotfree] += XBINPUT.sph_joint_damping Qsys[iirotfree] += XBINPUT.sph_joint_damping*dQdt[iirotfree] #XBOUT.Msys=Msys.copy('F') #XBOUT.Qsys=Qsys.copy('F') #XBOUT.Csys=Csys.copy('F') #XBOUT.Ksys=Ksys.copy('F') #Calculate system matrix for update calculation Asys = Ksys + Csys*gamma/(beta*dt) + Msys/(beta*dt**2) #Compute correction DQ[:] = np.dot(np.linalg.inv(Asys), -Qsys) Q += DQ dQdt += DQ*gamma/(beta*dt) dQddt += DQ/(beta*dt**2) #Update convergence criteria if XBOPTS.PrintInfo.value==True: sys.stdout.write('%-10.4e ' %(max(abs(Qsys)))) Res_Qglobal = max(abs(Qsys)) Res_DeltaX = max(abs(DQ)) ResLog10 = max(Res_Qglobal/Res0_Qglobal,Res_DeltaX/Res0_DeltaX) if XBOPTS.PrintInfo.value==True: sys.stdout.write('%-10.4e %8.4f\n' %(max(abs(DQ)),ResLog10)) #END Newton-Raphson # debug #XBOUT.ForceRigidList.append( np.dot(FrigidFull, Force_All).copy() ) #update to converged nodal displacements and velocities X=Q[:NumDof.value].copy('F') dXdt=dQdt[:NumDof.value].copy('F'); BeamLib.Cbeam3_Solv_State2Disp(XBINPUT, NumNodes_tot, XBELEM, XBNODE, PosIni, PsiIni, NumDof, X, dXdt,\ PosDefor, PsiDefor, PosDotDef, PsiDotDef) PosPsiTime[iStep+1,:3] = PosDefor[(NumNodes_tot.value-1)/2+1,:] PosPsiTime[iStep+1,3:] = PsiDefor[-1,XBELEM.NumNodes[-1]-1,:] #Position of all grid points in global FoR i1 = (iStep+1)*NumNodes_tot.value i2 = (iStep+2)*NumNodes_tot.value DynOut[i1:i2,:] = PosDefor #Export rigid-body velocities/accelerations if XBOPTS.OutInaframe.value==True: Vrel[iStep+1,:] = dQdt[NumDof.value:NumDof.value+6].copy('F') VrelDot[iStep+1,:] = dQddt[NumDof.value:NumDof.value+6].copy('F') else: Quat = dQdt[NumDof.value+6:].copy('F') Quat = Quat/np.linalg.norm(Quat) Cao = XbeamLib.Rot(Quat) ACoa[:3,:3] = np.transpose(Cao) ACoa[3:,3:] = np.transpose(Cao) Vrel[iStep+1,:] = np.dot(ACoa,dQdt[NumDof.value:NumDof.value+6].copy('F')) VrelDot[iStep+1,:] = np.dot(ACoa,dQddt[NumDof.value:NumDof.value+6].copy('F')) # sm: append outputs XBOUT.QuatList.append(Quat.copy()) # sm I/O: FoR A velocities/accelerations XBOUT.Time=Time # ...dyn.dat #XBOUT.PosPsiTime = PosPsiTime XBOUT.DynOut=DynOut # ...shape.dat XBOUT.Vrel=Vrel # ...rigid.dat XBOUT.VrelDot=VrelDot #XBOUT.PosPsiTime=PosPsiTime XBOUT.PsiList.append(PsiDefor.copy()) XBOUT.cputime.append( time.clock() - XBOUT.cputime[0] ) if SaveDict['SaveProgress']: iisave=np.arange(1,NumSteps.value,np.ceil(NumSteps.value/SaveDict['NumSavePoints'])) if any(iisave==iStep): PyLibs.io.save.h5file(SaveDict['OutputDir'], SaveDict['OutputFileRoot']+'.h5', *OutList) #END Time loop if SaveDict['Format'] == 'dat': PyLibs.io.dat.write_SOL912_final(Time, PosPsiTime, NumNodes_tot, DynOut, Vrel, VrelDot, SaveDict) if XBOPTS.PrintInfo.value==True: sys.stdout.write(' ... done\n') # sm I/O: FoR A velocities/accelerations XBOUT.Time=Time # ...dyn.dat XBOUT.PosPsiTime = PosPsiTime XBOUT.DynOut=DynOut # ...shape.dat XBOUT.Vrel=Vrel # ...rigid.dat XBOUT.VrelDot=VrelDot XBOUT.PosPsiTime=PosPsiTime # save h5 XBINPUT.ForceDyn = XBINPUT.ForceDyn + XBINPUT.ForceDyn_foll + XBINPUT.ForceDyn_dead del(XBINPUT.ForceDyn_dead) del(XBINPUT.ForceDyn_foll) PyLibs.io.save.h5file(SaveDict['OutputDir'], SaveDict['OutputFileRoot']+'.h5', *OutList) return XBOUT