// This code gives the mechanical vibration eigenfrequencies and eigenmodes of a // 3D disk that is clamped at its outer face and subject to proportional damping. #include "sparselizardbase.h" using namespace mathop; void sparselizard(void) { // The domain regions as defined in 'disk.geo': int vol = 1, sur = 2, top = 3; // The mesh can be curved! mesh mymesh("disk.msh"); // Nodal shape functions 'h1' with 3 components. // Field u is the membrane deflection. field u("h1xyz"); // Use interpolation order 2 on 'vol', the whole domain: u.setorder(vol, 2); // Clamp on surface 'sur' (i.e. 0 valued-Dirichlet conditions): u.setconstraint(sur); // E is Young's modulus. nu is Poisson's ratio. rho is the volumic mass. parameter E, nu, rho; E|vol = 150e9; nu|vol = 0.3; rho|vol = 2330; // Proportional damping C = alpha*M + beta*K: double alpha = 100, beta = 0.00006; formulation elasticity; // The linear elasticity formulation is classical and thus predefined: elasticity += integral(vol, predefinedelasticity(dof(u), tf(u), E, nu)); // Add the inertia terms: elasticity += integral(vol, -rho*dtdt(dof(u))*tf(u)); // Add the proportional damping terms to get damping matrix C = alpha*M + beta*K. // The mechanical equation can be written as M*dtdt(u) + C*dt(u) + K*u = 0. // All terms with a first order time derivative on the dof are added to C. elasticity += integral(vol, alpha * -rho*dt(dof(u))*tf(u)); elasticity += integral(vol, beta * predefinedelasticity(dt(dof(u)), tf(u), E, nu)); elasticity.generate(); // Get the stiffness, damping and mass matrix: mat K = elasticity.K(); mat C = elasticity.C(); mat M = elasticity.M(); // Remove the rows and columns corresponding to the 0 constraints: K.removeconstraints(); C.removeconstraints(); M.removeconstraints(); // In case of proportional damping this yields the same results: // C = alpha*M + beta*K; // Create the object to solve the second order polynomial eigenvalue problem (M*lambda^2 + C*lambda + K)u = 0 : eigenvalue eig(K, C, M); // Replace by eig(K, M) for an undamped simulation // Compute the 10 eigenvalues closest to the target magnitude 0.0 (i.e. the 10 first ones): eig.compute(10, 0.0); // Print the eigenfrequencies: eig.printeigenfrequencies(); // The eigenvectors are real only in the undamped case: std::vector myrealeigenvectors = eig.geteigenvectorrealpart(); std::vector myimageigenvectors = eig.geteigenvectorimaginarypart(); // Loop on all eigenvectors found: for (int i = 0; i < myrealeigenvectors.size(); i++) { // Transfer the data from the ith eigenvector to field u: u.setdata(vol, myrealeigenvectors[i]); // Write the deflection on the membrane with an order 2 interpolation: u.write(vol, "u"+std::to_string(i)+".vtk", 2); } // Code validation line. Can be removed. double checkval = eig.geteigenvaluerealpart()[1]*myimageigenvectors[3].norm(); std::cout << (checkval > -0.0029259 && checkval < -0.00292588); } int main(void) { SlepcInitialize(0,{},0,0); sparselizard(); SlepcFinalize(); return 0; }