main.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. // This code simulates the static deflection of an electrically actuated 2D micromembrane.
  2. // The problem is nonlinear because of the electrostatic-elastic coupling.
  3. //
  4. // The electrostatic problem and the electrostatic forces are computed on a mesh
  5. // deformed by the mechanical displacement. The mesh in the vacuum gap below the membrane
  6. // is deformed smoothly by solving an additional Laplace problem.
  7. //
  8. // The interpolation order for the electric potential field and mechanical displacement
  9. // is adapted to every geometrical region.
  10. #include "sparselizardbase.h"
  11. using namespace mathop;
  12. void sparselizard(void)
  13. {
  14. // The domain regions as defined in 'cmut2d.geo':
  15. int insulator = 1, pillars = 2, vacuumgap = 3, membrane = 4, ground = 5, clamp = 5, electrode = 6;
  16. // The mesh can be curved!
  17. mesh mymesh("cmut2d.msh");
  18. // Define the region for the mechanical problem:
  19. int solid = regionunion({insulator, pillars, membrane});
  20. // Define the region for the electric problem:
  21. int electricdomain = regionunion({insulator, pillars, membrane, vacuumgap});
  22. // Nodal shape functions 'h1' for the electric potential field v
  23. // and membrane deflection u (u has components x and y).
  24. // umesh smoothly deforms the mesh in the vacuum gap for a given membrane deflection.
  25. field u("h1xy"), umesh("h1xy"), v("h1");
  26. // Use interpolation order:
  27. //
  28. // - 3 for u on the membrane
  29. // - 2 for u on the pillars
  30. // - 1 elsewhere
  31. //
  32. // - 1 for the electric potential v
  33. //
  34. // Default order is 1.
  35. u.setorder(pillars, 2);
  36. u.setorder(membrane, 3);
  37. // Clamp and ground (i.e. 0 valued-Dirichlet conditions for u and v):
  38. u.setconstraint(clamp);
  39. v.setconstraint(ground);
  40. // Force the electric potential on the electrode to a close-to-pull-in voltage:
  41. v.setconstraint(electrode, 200);
  42. // E is Young's modulus. nu is Poisson's ratio.
  43. // epsilon is the electric permittivity.
  44. //
  45. // The membrane is polysilicon, the insulator is silicon dioxyde.
  46. parameter E, nu, epsilon;
  47. E|insulator = 70e9;
  48. E|pillars = 150e9;
  49. E|membrane = 150e9;
  50. nu|insulator = 0.17;
  51. nu|pillars = 0.3;
  52. nu|membrane = 0.3;
  53. epsilon|vacuumgap = 8.854e-12;
  54. epsilon|insulator = 3.9*8.854e-12;
  55. epsilon|pillars = 11.7*8.854e-12;
  56. epsilon|membrane = 11.7*8.854e-12;
  57. // An electrostatic formulation is used for the electric problem.
  58. // An elasticity formulation is used for the mechanical problem.
  59. formulation electrostatics, elasticity;
  60. // Weak electrostatic formulation, computed on the mesh deformed by field umesh:
  61. electrostatics += integral(electricdomain, umesh, epsilon*grad(dof(v))*grad(tf(v)));
  62. // The linear elasticity formulation is classical and thus predefined:
  63. elasticity += integral(solid, predefinedelasticity(dof(u), tf(u), E, nu, "planestrain"));
  64. // Electrostatic forces, computed on the elements of the whole electric domain
  65. // but with mechanical deflection test functions tf(u) only on solid.
  66. //
  67. // The electrostatic forces often appear in MEMS simulations and are thus predefined.
  68. // The inputs are the gradient of the test function of u defined on the mechanical domain,
  69. // the gradient of the previously computed electric potential field and the electric permittivity.
  70. //
  71. // The electrostatic forces are computed on the mesh deformed by field umesh.
  72. elasticity += integral(electricdomain, umesh, predefinedelectrostaticforce(tf(u,solid), grad(v), epsilon));
  73. // Solve the Laplace equation in the vacuum gap to smoothly deform the mesh.
  74. // umesh is forced to field u on region solid:
  75. umesh.setconstraint(solid, u);
  76. formulation laplacian;
  77. laplacian += integral(vacuumgap, grad(dof(compx(umesh)))*grad(tf(compx(umesh))) + grad(dof(compy(umesh)))*grad(tf(compy(umesh))) );
  78. // NONLINEAR ITERATION TO GET THE STATIC DEFLECTION:
  79. // Start with an all-zero solution vector for the elasticity formulation:
  80. vec solu(elasticity);
  81. double relresnorm = 1; int iter = 0;
  82. while (relresnorm > 1e-5)
  83. {
  84. electrostatics.generate();
  85. vec solv = solve(electrostatics.A(), electrostatics.b());
  86. // Transfer the data from the solution vector to the v field:
  87. v.setdata(electricdomain, solv);
  88. // Write the electric field with an order 1 interpolation (default).
  89. // The electric field is computed and saved on the geometry deformed by umesh.
  90. (-grad(v)).write(electricdomain, umesh, "E.pos");
  91. // Use the now known electric potential v to compute the membrane deflection:
  92. elasticity.generate();
  93. vec b = elasticity.b();
  94. mat A = elasticity.A();
  95. // Compute the norm of the relative residual:
  96. relresnorm = (b-A*solu).norm()/b.norm();
  97. solu = solve(A,b);
  98. u.setdata(solid, solu);
  99. // Write the deflection u with an order 3 interpolation:
  100. u.write(solid, "u.pos", 3);
  101. // Smooth the mesh on the vacuum gap:
  102. laplacian.generate();
  103. vec solumesh = solve(laplacian.A(), laplacian.b());
  104. // Save the smoothed mesh on the vacuum region:
  105. umesh.setdata(vacuumgap, solumesh);
  106. // Also save the u field on region solid to umesh.
  107. // This is done by selecting field u with |u on the solu vector.
  108. umesh.setdata(solid, solu|u);
  109. umesh.write(electricdomain, "umesh.pos", 3);
  110. // Print the iteration number and relative residual norm:
  111. std::cout << "Relative residual norm @iteration " << iter << " is " << relresnorm << std::endl;
  112. iter++;
  113. }
  114. // Code validation line. Can be removed.
  115. std::cout << (compy(grad(v)).integrate(vacuumgap, u, 4) < 0.0022901 && compy(grad(v)).integrate(vacuumgap, u, 4) > 0.0022900);
  116. }
  117. int main(void)
  118. {
  119. SlepcInitialize(0,{},0,0);
  120. sparselizard();
  121. SlepcFinalize();
  122. return 0;
  123. }