main.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  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. u.setorder(membrane, 3);
  34. u.setorder(vacuumgap, 3);
  35. u.setorder(pillars, 2);
  36. u.setorder(insulator, 1);
  37. v.setorder(electricdomain, 1);
  38. umesh.setorder(solid, 1);
  39. umesh.setorder(electricdomain, 1);
  40. // Clamp and ground (i.e. 0 valued-Dirichlet conditions for u and v):
  41. u.setconstraint(clamp);
  42. v.setconstraint(ground);
  43. // Force the electric potential on the electrode to a close-to-pull-in voltage:
  44. v.setconstraint(electrode, 200);
  45. // E is Young's modulus. nu is Poisson's ratio.
  46. // epsilon is the electric permittivity.
  47. //
  48. // The membrane is polysilicon, the insulator is silicon dioxyde.
  49. parameter E, nu, epsilon;
  50. E|insulator = 70e9;
  51. E|pillars = 150e9;
  52. E|membrane = 150e9;
  53. nu|insulator = 0.17;
  54. nu|pillars = 0.3;
  55. nu|membrane = 0.3;
  56. epsilon|vacuumgap = 8.854e-12;
  57. epsilon|insulator = 3.9*8.854e-12;
  58. epsilon|pillars = 11.7*8.854e-12;
  59. epsilon|membrane = 11.7*8.854e-12;
  60. // An electrostatic formulation is used for the electric problem.
  61. // An elasticity formulation is used for the mechanical problem.
  62. formulation electrostatics, elasticity;
  63. // Weak electrostatic formulation, computed on the mesh deformed by field umesh:
  64. electrostatics += integral(electricdomain, umesh, epsilon*grad(dof(v))*grad(tf(v)));
  65. // The linear elasticity formulation is classical and thus predefined:
  66. elasticity += integral(solid, predefinedelasticity(dof(u), tf(u), E, nu, "planestrain"));
  67. // Electrostatic forces, computed on the elements of the whole electric domain
  68. // but with mechanical deflection test functions tf(u) only on solid.
  69. //
  70. // The electrostatic forces often appear in MEMS simulations and are thus predefined.
  71. // The inputs are the gradient of the test function of u defined on the mechanical domain,
  72. // the gradient of the previously computed electric potential field and the electric permittivity.
  73. //
  74. // The electrostatic forces are computed on the mesh deformed by field umesh.
  75. elasticity += integral(electricdomain, umesh, predefinedelectrostaticforce(tf(u,solid), grad(v), epsilon));
  76. // Solve the Laplace equation in the vacuum gap to smoothly deform the mesh.
  77. // umesh is forced to field u on region solid:
  78. umesh.setconstraint(solid, u);
  79. formulation laplacian;
  80. laplacian += integral(vacuumgap, grad(dof(compx(umesh)))*grad(tf(compx(umesh))) + grad(dof(compy(umesh)))*grad(tf(compy(umesh))) );
  81. // NONLINEAR ITERATION TO GET THE STATIC DEFLECTION:
  82. // Start with an all-zero solution vector for the elasticity formulation:
  83. vec solu(elasticity);
  84. double relresnorm = 1; int iter = 0;
  85. while (relresnorm > 1e-5)
  86. {
  87. electrostatics.generate();
  88. vec solv = solve(electrostatics.A(), electrostatics.b());
  89. // Transfer the data from the solution vector to the v field:
  90. v.setdata(electricdomain, solv);
  91. // Write the electric field with an order 1 interpolation (default).
  92. // The electric field is computed and saved on the geometry deformed by umesh.
  93. (-grad(v)).write(electricdomain, umesh, "E.pos");
  94. // Use the now known electric potential v to compute the membrane deflection:
  95. elasticity.generate();
  96. vec b = elasticity.b();
  97. mat A = elasticity.A();
  98. // Compute the norm of the relative residual:
  99. relresnorm = (b-A*solu).norm()/b.norm();
  100. solu = solve(A,b);
  101. u.setdata(solid, solu);
  102. // Write the deflection u with an order 3 interpolation:
  103. u.write(solid, "u.pos", 3);
  104. // Smooth the mesh on the vacuum gap:
  105. laplacian.generate();
  106. vec solumesh = solve(laplacian.A(), laplacian.b());
  107. // Save the smoothed mesh on the vacuum region:
  108. umesh.setdata(vacuumgap, solumesh);
  109. // Also save the u field on region solid to umesh.
  110. // This is done by selecting field u with |u on the solu vector.
  111. umesh.setdata(solid, solu|u);
  112. umesh.write(electricdomain, "umesh.pos", 3);
  113. // Print the iteration number and relative residual norm:
  114. std::cout << "Relative residual norm @iteration " << iter << " is " << relresnorm << std::endl;
  115. iter++;
  116. }
  117. // Code validation line. Can be removed.
  118. std::cout << (compy(grad(v)).integrate(vacuumgap, u, 4) < 0.0022905 && compy(grad(v)).integrate(vacuumgap, u, 4) > 0.0022901);
  119. }
  120. int main(void)
  121. {
  122. SlepcInitialize(0,{},0,0);
  123. sparselizard();
  124. SlepcFinalize();
  125. return 0;
  126. }