GRIT
'Hello, world'
Vortex in a box
Tutorial output

Python tutorials

The GRIT project is setup such that all binaries/executables are generated in the 'GRIT/bin' folder, this includes the dynamic library needed to run the Python interface. So when you want to run the example/tutorial code, you need to do so from the bin folder.

A 'Hello, world' example

As is traditional, we will start out with a 'Hallo, world' type of example. First, set up your imports.

import pygrit as GRIT
import numpy as np
import math

Define a main function.

def main():
  print('My hello pybind')
if __name__ == "__main__":
 main()

Save as 'hello.py' and run the script from the 'bin' folder using the command 'python hello.py'.

GRIT uses configuration files to pass arguments at runtime, so we start out by importing the settings given in 'example.cfg'.

def main():
  print('My hello pybind')
  cfg_filename = 'example.cfg'
  settings = GRIT.ConfigFile()
  settings.load(cfg_filename)

The setting are loaded in to the 'ConfigFile' object, ready to be used.

Extract filename from settings, and turn settings into parameters.

...
txt_filename = settings.get_value('txt_filename', 'circle_enright.txt')
parameters = GRIT.make_parameters_from_config_file(settings)

Now we have what we need to initialize a GRIT engine.

engine = GRIT.Engine2D()
GRIT.init_engine_with_mesh_file(
       GRIT.get_data_file_path(txt_filename)
       , parameters
       , engine
       )

A quick look at the output, reveals - as is often the case with 'Hello, world' type examples - at first glance a rather boring result. However, if you get this to work, you are well on your way to making your own GRIT simulations.

Vortex in a box

In its simplest form, a GRIT simulation can be described as a four step process:

  1. Initialize system
  2. Do simulation step
  3. Update the engine
  4. Write simulation result
Repeat steps 2 - 4 as many times as needed.

Initialize

As in the 'Hello, world' example, we start with importing the libraries we need and setting up the variables used to initialize a GRIT engine.

def main():
  cfg_filename = 'tutorial_vortex_in_a_box.cfg'

  settings = GRIT.ConfigFile()
  settings.load(cfg_filename)

  parameters = GRIT.make_parameters_from_config_file(settings)

  txt_filename = settings.get_value('txt_filename', 'circle_enright.txt')
  output_path = settings.get_value('output_path', '')
  max_steps = int(settings.get_value('steps', '100'))

  engine = GRIT.Engine2D()

  GRIT.init_engine_with_mesh_file(
         GRIT.get_data_file_path(txt_filename)
         , parameters
         , engine
         )

Simulation step

The simulation step is where the real work is done, let's put that in a separate function to keep the 'main' function clean.
The simulation step function takes the engine and the settings object as input. First, all necessary information is extracted from the engine object; the number of vertices in the mesh and the vertices of the mesh. A time step - dt - is set, and a copy of the vertices is made.

def do_simulation_step(engine, settings):
 object_label = int(settings.get_value('object_label', '1'))
 phase = GRIT.make_phase(engine, object_label)

 N = np.asanyarray(phase.get_vertices()).size

 px = np.resize(np.array([]),N)
 py = np.resize(np.array([]),N)
 GRIT.get_sub_range_current(engine, phase, px, py)

 dt = 0.01

 px_new = np.array(px)
 py_new = np.array(py)

Next, we add a velocity to the vertices to update their positions and return to the main function.

for i in range(0, N):
  x = px[i]
  y = py[i]
  u = 2.0 * math.cos(math.pi * y) * math.sin(math.pi * y) * math.sin(math.pi*x) * math.sin(math.pi*x)
  v = -2.0 * math.cos(math.pi * x) * math.sin(math.pi * x) * math.sin(math.pi*y) * math.sin(math.pi*y)
  px_new[i] = px[i] + u*dt
  py_new[i] = py[i] + v*dt

  GRIT.set_sub_range_target(engine, phase, px_new, py_new)

Back in the main function, we loop over the number of steps given by the configuration file. Each iteration of the loop repeats steps 2-4, where 'engine.update(parameters)' is the call to GRIT where all the magic happens.

for i in range(1, max_steps):
  do_simulation_step(engine, settings)
  engine.update(parameters)
  write_svg_files(engine, parameters, output_path, i)

All that is left to do, is to somehow record the simulation results. In this example - and in the demos in the repository - we write the results to an .svg file using the function 'write_svg_files'. GRIT is not a realtime simulation tool, and so it makes more sense to save the results as files rather than visualizing each frame when it is computed. The implementation of 'write_svg_files' is simple.

def write_svg_files(engine, parameters, output_path, frame_number):
  filename = output_path + GRIT.generate_filename('/tutorial_vortex_in_a_box', frame_number, 'svg')
  GRIT.svg_draw(filename, engine, parameters)

The full example can be found in the GitHub repository (see 'Download') or here as a .zip file.

Tutorial output

When you build all targets, the 'GRIT/bin' folder will contain a number of tutorials/demos. The following videos are the results of running these tutorials/demos.

demo_area_maximization

demo_elasticity_compression

demo_elasticity_squeezer

demo_elasticity_stretch

demo_tutorial_contact

demo_tutorial_smolarkiewicz

demo_tutorial_vortex_in_a_box

demo_tutorial_zalesak_disk