main.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. // This code simulates the laminar, incompressible water flow past a step.
  2. //
  3. // A parabolic normal flow velocity is forced at the inlet and
  4. // a zero pressure is imposed at the outlet.
  5. //
  6. // P-adaptivity is used.
  7. //
  8. // More information for this benchmark example can be found in:
  9. //
  10. // "Finite element methods for the incompressible Navier-Stokes equations", A. Segal
  11. //
  12. // The step geometry is as follows:
  13. //
  14. // l2
  15. // <--------------------------------->
  16. // __________________________________
  17. // | /|\
  18. // l1 | |
  19. // <----------->| |
  20. // _____________| h2 \|/
  21. // /|\ OUTLET
  22. // |
  23. // INLET |
  24. // \|/ h1
  25. // ________________________________________________
  26. #include "sparselizardbase.h"
  27. using namespace mathop;
  28. // First four arguments give the geometry dimension, last four arguments give the mesh size:
  29. mesh createmesh(double l1, double h1, double l2, double h2, int nl1, int nl2, int nh1, int nh2);
  30. void sparselizard(void)
  31. {
  32. // Region numbers used in this simulation:
  33. int fluid = 1, inlet = 2, outlet = 3, skin = 4;
  34. // Height of the inlet [m]:
  35. double h1 = 1e-3;
  36. mesh mymesh = createmesh(2e-3, h1, 12e-3, 1e-3, 5, 15, 8, 8);
  37. // Define the fluid wall (not including the inlet and outlet):
  38. int wall = regionexclusion(skin, regionunion({inlet,outlet}));
  39. // Dynamic viscosity of water [Pa.s] and density [kg/m3]:
  40. double mu = 8.9e-4, rho = 1000;
  41. // Field v is the flow velocity. It uses nodal shape functions "h1" with two components.
  42. // Field p is the relative pressure. Fields x and y are the space coordinates.
  43. field v("h1xy"), p("h1"), x("x"), y("y");
  44. // Force the flow velocity to 0 on the wall:
  45. v.setconstraint(wall);
  46. // Set a 0 relative pressure at the outlet:
  47. p.setconstraint(outlet);
  48. // Use an order 1 interpolation for p and 2 for v on the fluid region (satisfies the BB condition).
  49. // This must be added before the p-adaptivity 'setorder' calls below to compute the initial criterion.
  50. p.setorder(fluid, 1);
  51. v.setorder(fluid, 2);
  52. // The interpolation order of the pressure and velocity fields is adapted based on a criterion.
  53. // The v field will trigger the p-adaptivity every time its value changes.
  54. // With the selected orders (1 to 3 for p and 2 to 4 for v) the BB condition is always satisfied.
  55. expression adaptcriterion = norm(grad(compx(v))) + norm(grad(compy(v)));
  56. p.setorder(adaptcriterion, {v}, 1, 3);
  57. v.setorder(adaptcriterion, {v}, 2, 4);
  58. // Define the weak formulation for incompressible laminar flow:
  59. formulation laminarflow;
  60. laminarflow += integral(fluid, predefinednavierstokes(dof(v), tf(v), v, dof(p), tf(p), mu, rho, 0, 0) );
  61. // This loop with the above formulation is a Newton iteration:
  62. int index = 0; double convergence = 1, velocity = 0.1;
  63. while (convergence > 1e-10)
  64. {
  65. // Slowly increase the velocity for a high Reynolds (1 m/s flow, 1000 Reynolds still converges).
  66. if (velocity < 0.299)
  67. velocity = velocity + 0.008;
  68. std::cout << "Flow velocity: " << velocity << " m/s" << std::endl;
  69. // Force the flow velocity at the inlet (quadratic profile w.r.t. the y axis):
  70. v.setconstraint(inlet, array2x1(velocity*y*(h1-y)/pow(h1*0.5,2), 0));
  71. // Get a measure of the solution for convergence evaluation:
  72. double measuresol = norm(v).integrate(fluid,2);
  73. // Generate and solve the laminar flow problem then save to the fields:
  74. solve(laminarflow);
  75. convergence = std::abs((norm(v).integrate(fluid,2) - measuresol)/norm(v).integrate(fluid,2));
  76. std::cout << "Relative solution change: " << convergence << std::endl;
  77. // Write the fields to file. Write v with an order 3 interpolation.
  78. p.write(fluid, "p"+std::to_string(index)+".vtk");
  79. v.write(fluid, "v"+std::to_string(index)+".vtk", 3);
  80. getfieldorder(v.compx()).write(fluid, "fieldorderv"+std::to_string(index)+".vtk");
  81. index++;
  82. }
  83. // Compute the flow velocity norm at position (5,1,0) mm in space:
  84. double vnorm = norm(v).interpolate(fluid, {5e-3, 1e-3, 0.0})[0];
  85. // Output the input and output flowrate for a unit width:
  86. double flowratein = (normal(inlet)*v).integrate(inlet, 4);
  87. double flowrateout = -(normal(outlet)*v).integrate(outlet, 4);
  88. std::cout << std::endl << "Flowrate in/out for a unit width: " << flowratein << " / " << flowrateout << " m^3/s" << std::endl;
  89. // Code validation line. Can be removed.
  90. std::cout << (vnorm*flowrateout < 2.60974e-05 && vnorm*flowrateout > 2.60970e-05);
  91. }
  92. mesh createmesh(double l1, double h1, double l2, double h2, int nl1, int nl2, int nh1, int nh2)
  93. {
  94. int fluid = 1, inlet = 2, outlet = 3, skin = 4;
  95. shape qthinleft("quadrangle", fluid, {0,0,0, l1,0,0, l1,h1,0, 0,h1,0}, {nl1,nh1,nl1,nh1});
  96. shape qthinright("quadrangle", fluid, {l1,0,0, l1+l2,0,0, l1+l2,h1,0, l1,h1,0}, {nl2,nh1,nl2,nh1});
  97. shape qthick("quadrangle", fluid, {l1,h1,0, l1+l2,h1,0, l1+l2,h1+h2,0, l1,h1+h2,0}, {nl2,nh2,nl2,nh2});
  98. shape linlet = qthinleft.getsons()[3];
  99. linlet.setphysicalregion(inlet);
  100. shape loutlet = shape("union", outlet, {qthick.getsons()[1],qthinright.getsons()[1]});
  101. mesh mymesh;
  102. mymesh.regionskin(skin, fluid);
  103. mymesh.load({qthinleft,qthinright,qthick,linlet,loutlet});
  104. mymesh.write("pipestep.msh");
  105. return mymesh;
  106. }
  107. int main(void)
  108. {
  109. SlepcInitialize(0,{},0,0);
  110. sparselizard();
  111. SlepcFinalize();
  112. return 0;
  113. }