Download :download:`this testcase <2d_lid_driven_cavity.py>`.

2D lid-driven cavity flow
=========================
This example simulates a 2D lid-driven cavity flow using the Finite Element Method (FEM) with a P1-P1 representation.


Keywords
--------
FEM, lid driven cavity, 2D, fluid

Description
-----------
The test demonstrates:
- How to perform a FEM simulation in a fixed domain

.. code-block:: python
  
  import os, sys, shutil
  import numpy as np
  import gmsh
  from migflow import fluid
  

Output Directory
----------------
Create a clean output directory for simulation results.

.. code-block:: python
  
  outputdir = "output" if len(sys.argv) < 2 else sys.argv[1]
  shutil.rmtree(outputdir, ignore_errors=True)
  os.makedirs(outputdir)
  
  

Geometrical parameters and mesh generation
------------------------------------------

.. code-block:: python
  
  l_box = 1.0
  h_box = 1.0
  

Mesh parameters
---------------

.. code-block:: python
  
  mesh_size = l_box / 80
  
  
  def gen_mesh(width, height, mesh_size, origin=np.array([0, 0])):
      """Generate a rectangular 2D mesh with named boundaries."""
      origin = np.asarray(origin)
      gmsh.model.add("box")
      gmsh.model.occ.add_rectangle(origin[0], origin[1], 0, width, height)
      gmsh.model.occ.synchronize()
  
      def get_line(x0, x1, eps=1e-6):
          r = gmsh.model.get_entities_in_bounding_box(
              x0[0] - eps, x0[1] - eps, -eps, x1[0] + eps, x1[1] + eps, eps, 1
          )
          return [tag for dim, tag in r]
  
      h, w = height, width
      gmsh.model.add_physical_group(
          1, get_line(origin + [0, 0], origin + [w, 0]), name="bottom"
      )
      gmsh.model.add_physical_group(
          1, get_line(origin + [0, h], origin + [w, h]), name="top"
      )
      gmsh.model.add_physical_group(
          1, get_line(origin + [0, 0], origin + [0, h]), name="left"
      )
      gmsh.model.add_physical_group(
          1, get_line(origin + [w, 0], origin + [w, h]), name="right"
      )
      gmsh.model.add_physical_group(2, [1], name="domain")
      gmsh.model.mesh.set_size_callback(lambda dim, tag, x, y, z, lc: mesh_size)
      gmsh.model.mesh.generate(2)
  
  
  gen_mesh(l_box, h_box, mesh_size)

Physical Parameters
-------------------

.. code-block:: python
  
  g = np.array([0.0, 0.0])
  rho = 1000
  mu = 1e-3
  Re = 1000
  v_top = Re * mu / (rho * l_box)

Time parameters
---------------

.. code-block:: python
  
  cfl = 1
  U = v_top
  U_init = v_top
  dt = mesh_size / U * cfl
  t = 0
  tEnd = 25000.0
  

Fluid problem
-------------

.. code-block:: python
  
  f = fluid.FluidProblem(2, g, mu, rho)
  f.load_msh(None)
  f.set_wall_boundary("bottom", velocity=[0, 0])
  f.set_wall_boundary("right", velocity=[0, 0])
  f.set_wall_boundary("top", velocity=[v_top, 0])
  f.set_wall_boundary("left", velocity=[0, 0])
  f.set_strong_boundary("top", velocity=[v_top, 0])
  f.set_strong_boundary("bottom", velocity=[0, 0])
  f.set_strong_boundary("left", velocity=[0, 0])
  f.set_strong_boundary("right", velocity=[0, 0])

Simulation Loop
---------------
Time integration loop.

.. code-block:: python
  
  i = 0
  outf = 25
  while t < tEnd:
      print(f"{i:4d}, {t:.6g}/{tEnd:.6g}, {dt:.6g}")
      if i % outf == 0:  # or t > 0.3:
          f.write_mig(outputdir, t)
      f.implicit_euler(dt)
      t += dt
      i += 1
  

Plot
----
.. code-block:: shell

 python3 -m migflow.plot.migplot output --actors fluid --fluid-field velocity --fluid-vmin 0 --fluid-vmax 0.001

