def Solve_F90(XBINPUT,XBOPTS): """@brief Nonlinear static structural solver using f90 solve routine.""" "Check correct solution code" assert XBOPTS.Solution.value == 112, ('NonlinearStatic (F90) 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 (using .f90 routines) ... \n') BeamLib.Cbeam3_Solv_NonlinearStatic(XBINPUT, XBOPTS, NumNodes_tot, XBELEM,\ PosIni, PsiIni, XBNODE, NumDof,\ PosDefor, PsiDefor) 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_F90(XBINPUT, XBOPTS): """@brief Nonlinear dynamic structural solver using f90 solve routine.""" "Check correct solution code" assert XBOPTS.Solution.value == 312, ('NonlinearDynamic (F90) requested' +\ ' with wrong solution code') "Initialise variables for static analysis" XBINPUT, XBOPTS, NumNodes_tot, XBELEM, PosIni, PsiIni, XBNODE, NumDof \ = BeamInit.Static(XBINPUT, XBOPTS) "Change solution code to NonlinearStatic" XBOPTS.Solution.value = 112 "Set initial conditions as undef config" PosDefor = PosIni.copy(order='F') PsiDefor = PsiIni.copy(order='F') "Solve static" BeamLib.Cbeam3_Solv_NonlinearStatic(XBINPUT, XBOPTS, NumNodes_tot, XBELEM,\ PosIni, PsiIni, XBNODE, NumDof,\ PosDefor, PsiDefor) "Change solution code back to NonlinearDynamic" 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) "Change solution code to NonlinearDynamic" XBOPTS.Solution.value = 312 "Initialise variables for dynamic analysis" Time, NumSteps, ForceTime, ForcedVel, ForcedVelDot,\ PosDotDef, PsiDotDef,\ OutGrids, PosPsiTime, VelocTime, DynOut\ = BeamInit.Dynamic(XBINPUT,XBOPTS) "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 "Solve dynamic using f90 solver" BeamLib.Cbeam3_Solv_NonlinearDynamic(XBINPUT, XBOPTS, NumNodes_tot, XBELEM,\ PosIni, PsiIni, XBNODE, NumDof,\ PosDefor, PsiDefor,\ NumSteps, Time, ForceTime, ForcedVel, ForcedVelDot,\ PosDotDef, PsiDotDef,\ PosPsiTime, VelocTime, DynOut, OutGrids) "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()
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_F90_steps(XBINPUT, XBOPTS): """@brief Nonlinear dynamic structural solver with time-steps controlled in Python but solved using F90 routines at each time-step.""" "Check correct solution code" assert XBOPTS.Solution.value == 312, ('NonlinearDynamic (F90) requested' +\ ' with wrong solution code') "Initialise variables for static analysis" XBINPUT, XBOPTS, NumNodes_tot, XBELEM, PosIni, PsiIni, XBNODE, NumDof \ = BeamInit.Static(XBINPUT, XBOPTS) "Change solution code to NonlinearStatic" XBOPTS.Solution.value = 112 "Set initial conditions as undef config" PosDefor = PosIni.copy(order='F') PsiDefor = PsiIni.copy(order='F') "Solve static" BeamLib.Cbeam3_Solv_NonlinearStatic(XBINPUT, XBOPTS, NumNodes_tot, XBELEM,\ PosIni, PsiIni, XBNODE, NumDof,\ PosDefor, PsiDefor) "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) "Change solution code to NonlinearDynamic" XBOPTS.Solution.value = 312 "Initialise variables for dynamic analysis" Time, NumSteps, ForceTime, ForcedVel, ForcedVelDot,\ PosDotDef, PsiDotDef,\ OutGrids, PosPsiTime, VelocTime, DynOut\ = BeamInit.Dynamic(XBINPUT,XBOPTS) "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 "Save time-dependant variables with only one time step (2 time-steps)" TimeElements = Time[0:2].copy('F') Ftime = ForceTime[0:2].copy('F') Fvel = ForcedVel[0:2, :].copy('F') FvelDot = ForcedVelDot[0:2, :].copy('F') "Create Output vectors, one for each time-step" PosPsiTimeStep = PosPsiTime[0:2, :].copy('F') VelocTimeStep = VelocTime[0:2, :].copy('F') DynOutStep = DynOut[0:2 * NumNodes_tot.value, :].copy('F') "Initialise and approximate initial 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') "Start Time-loop" for TimeStep in range(0, NumSteps.value): "Update 2-step time arrays" TimeElements = Time[TimeStep:TimeStep + 2] Ftime = ForceTime[TimeStep:TimeStep + 2] Fvel[:, :] = ForcedVel[TimeStep:TimeStep + 2, :] FvelDot[:, :] = ForcedVelDot[TimeStep:TimeStep + 2, :] "Solve dynamic step using f90 solver" BeamLib.Cbeam3_Solv_NonlinearDynamicAccel(XBINPUT, XBOPTS, NumNodes_tot,\ XBELEM,PosIni, PsiIni, XBNODE, NumDof,\ PosDefor, PsiDefor,\ ct.c_int(1), TimeElements, Ftime, Fvel, FvelDot,\ PosDotDef, PsiDotDef,\ PosDotDotDef, PsiDotDotDef,\ PosPsiTimeStep, VelocTimeStep, DynOutStep, OutGrids) "Append output information" PosPsiTime[TimeStep + 1, :] = PosPsiTimeStep[1, :] VelocTime[TimeStep + 1, :] = VelocTimeStep[1, :] DynOut[(TimeStep)*NumNodes_tot.value:(TimeStep+1)*NumNodes_tot.value-1,\ : ] = DynOutStep[NumNodes_tot.value:2*NumNodes_tot.value-1] "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()
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. @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_F90(XBINPUT, XBOPTS): """@brief Nonlinear dynamic structural solver using f90 solve routine.""" #Check correct solution code assert XBOPTS.Solution.value == 912, ('NonlinearDynamic (F90) requested' +\ ' with wrong solution code') #Initialise variables for static analysis XBINPUT, XBOPTS, NumNodes_tot, XBELEM, PosIni, PsiIni, XBNODE, NumDof \ = BeamInit.Static(XBINPUT, XBOPTS) #Change solution code to NonlinearStatic XBOPTS.Solution.value = 112 #Set initial conditions as undef config PosDefor = PosIni.copy(order='F') PsiDefor = PsiIni.copy(order='F') #Solve static BeamLib.Cbeam3_Solv_NonlinearStatic(XBINPUT, XBOPTS, NumNodes_tot, XBELEM,\ PosIni, PsiIni, XBNODE, NumDof,\ PosDefor, PsiDefor) #Change solution code back to NonlinearDynamic 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, ForcedVel, ForcedVelDot,\ PosDotDef, PsiDotDef,\ OutGrids, PosPsiTime, VelocTime, DynOut\ = BeamInit.Dynamic(XBINPUT,XBOPTS, NumNodes_tot) # Delete unused variables. del PosPsiTime, VelocTime #Initialise quaternions for rigid-body dynamics Quat = np.zeros(4, ct.c_double, 'F') Quat[0] = 1.0 #Write _force file ofile = Settings.OutputDir + Settings.OutputFileRoot + '_SOL912_force.dat' fp = open(ofile, 'w') BeamIO.Write_force_File(fp, Time, ForceTime, ForcedVel, ForcedVelDot) fp.close() #Solve dynamic using f90 solver BeamLib.Xbeam_Solv_FreeNonlinDynamic(XBINPUT, XBOPTS, NumNodes_tot, XBELEM,\ PosIni, PsiIni, XBNODE, NumDof,\ PosDefor, PsiDefor, Quat,\ NumSteps, Time, ForceTime, ForcedVel, ForcedVelDot,\ PosDotDef, PsiDotDef, DynOut, OutGrids) #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, ForcedVel, ForcedVelDot) fp.close()
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_F90_steps(XBINPUT,XBOPTS): """@brief Nonlinear static structural solver using f90 solve routine called once per load-step.""" "Check correct solution code" assert XBOPTS.Solution.value == 112, ('NonlinearStatic (F90) 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 (using .f90 routine at' +\ ' each load-step) ... \n') "Initialise load increments and set F90 load-step to 1" LoadSteps = XBOPTS.NumLoadSteps.value LoadIncrement = XBINPUT.ForceStatic/LoadSteps XBOPTS.NumLoadSteps.value = 1 "Start loading loop" for step in range(1,LoadSteps+1): "Current load to be applied" XBINPUT.ForceStatic = step*LoadIncrement "Print load step" if XBOPTS.PrintInfo.value == True: print(' Python-based outer load step %d' %(step)) "Solve with one load step" BeamLib.Cbeam3_Solv_NonlinearStatic(XBINPUT, XBOPTS, NumNodes_tot, XBELEM,\ PosIni, PsiIni, XBNODE, NumDof,\ PosDefor, PsiDefor) 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 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