Download :download:`this example <../../examples/tetris.py>`.

.. code-block:: python
  
  # MigFlow - Copyright (C) <2010-2026>
  # <Universite catholique de Louvain (UCL), Belgium
  #  Universite de Montpellier, France>
  #
  # List of the contributors to the development of MigFlow: see AUTHORS file.
  # Description and complete License: see LICENSE file.
  #
  # This program (MigFlow) is free software:
  # you can redistribute it and/or modify it under the terms of the GNU Lesser General
  # Public License as published by the Free Software Foundation, either version
  # 3 of the License, or (at your option) any later version.
  #
  # This program is distributed in the hope that it will be useful,
  # but WITHOUT ANY WARRANTY; without even the implied warranty of
  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  # GNU Lesser General Public License for more details.
  #
  # You should have received a copy of the GNU Lesser General Public License
  # along with this program (see COPYING and COPYING.LESSER files).  If not,
  # see <http://www.gnu.org/licenses/>.
  

Tetris
==============================================
This examples illustrates how to define a particle problem in which bodies are tetriminoes falling into a open box.

.. code-block:: python
  
  import os
  import time
  import shutil
  import random
  import numpy as np
  from migflow import scontact
  random.seed(0)
  

First, let's create the output directory.

.. code-block:: python
  
  outputdir = "output-tetris"
  shutil.rmtree(outputdir, True)
  os.makedirs(outputdir)
  

Piece Generation
----------------
Let's define a function to generate any piece.

.. code-block:: python
  
  def add_piece(p, r, initial_coord):
      """ Creates a tetrimino piece into the MigFlow particle problem.
  
          Keyword arguments:
          p -- the particle problem
          r -- particle radius
          initial_coord -- initial coordinates of the body
      """

Each piece is defined by its mask over a 2x4 rectangular grid.

.. code-block:: python
  
      models = [
          [[1, 0, 0, 0],
           [1, 1, 1, 0]],
  
          [[0, 0, 0, 1],
           [0, 1, 1, 1]],
  
          [[1, 1, 1, 1],
           [0, 0, 0, 0]],
  
          [[0, 1, 1, 0],
           [0, 1, 1, 0]],
  
          [[0, 0, 1, 1],
           [0, 1, 1, 0]],
  
          [[0, 1, 0, 0],
           [1, 1, 1, 0]],
  
          [[0, 1, 1, 0],
           [0, 0, 1, 1]]
      ]

A piece is randomly selected and its position and initial rotation are prescribed.

.. code-block:: python
  
      piece = random.choice(models)
      omega = 10*np.pi*(-1+2*random.random())
      y, x = np.where(piece)
      x = r*(initial_coord[0]+2*x)
      y = r*(initial_coord[1]+2*y)

A body representing the piece is generated. The body is composed of 4 particles.

.. code-block:: python
  
      R = np.repeat(r, 4)                                     # particles radii
      coord = np.column_stack([x, y])                         # particles coordinates
      body = p.add_particle_body(coord, R, np.pi*R**2*rho)    # create body and particles
      p.body_omega()[body, 0] = omega                         # Set body rotations
  

Particle Problem
----------------
The particle problem based is created, its dimension has to be provided.

.. code-block:: python
  
  p = scontact.ParticleProblem(2)

Let's define the particle properties :

.. code-block:: python
  
  g = np.array([0, -9.81])                                    # gravity
  rho = 1000                                                  # particle density
  r = 0.05                                                    # particle radius
  h = 2                                                       # box height
  w = 2                                                       # box width
  x0 = np.array([-3, 40])                                     # initial position

The open box is defined using three segments.

.. code-block:: python
  
  p.add_boundary_segment([-w/2, -h/2], [-w/2,  h/2], "bnd")
  p.add_boundary_segment([ w/2,  h/2], [ w/2, -h/2], "bnd")
  p.add_boundary_segment([ w/2, -h/2], [-w/2, -h/2], "bnd")

To activate the body contact algorithm the fixed contact geometry flag is set to 0.

.. code-block:: python
  
  p.set_fixed_contact_geometry(0)

An initial piece is inserted into the domain :

.. code-block:: python
  
  add_piece(p, r, x0)

Time integration
----------------
The numerical parameters is given and the initial conditions are written in the output directory.
number of iterations between output files

.. code-block:: python
  
  outf = 15
  dt = 1e-3                                                   # time step
  tEnd = 20                                                   # final time
  t = 0                                                       # intial time
  ii = 0                                                      # initial iteration
  p.write_mig(outputdir, t)                                   # write the intial particle problem
  tic = time.process_time()                                   # create a timer

The computational loop can start.

.. code-block:: python
  
  while t < tEnd:
      forces = g*(np.pi*p.r()**2*rho)                         # external particle forces
      p.iterate(dt, forces, tol=1e-7)                         # Contact solver
      t += dt
      # Output files writing
      if ii%outf == 0:
          p.write_mig(outputdir, t)                           # write the output data
      ii += 1
      # Add a new piece
      if ii%250 == 0:
          add_piece(p, r, x0)                                 # add a piece
      print("%i : %.2g/%.2g (cpu %.6g)" % (ii, t, tEnd, time.process_time() - tic))
