2D Hydrodynamics - Pair of Vortices#

Problem setup#

In this 2D hydrodynamics simulation, we initialize a pair of vortices using the following velocity field components in Fourier space:

U.Vkx[1,0] = 0+0j
U.Vkz[1,0] = -1+0j
U.Vkx[0,1] = 1+0j
U.Vkz[0,1] = 0+0j

These initial conditions set up a pair of counter-rotating vortices, which will evolve over time according to the specified simulation parameters.

Specifying parameters#

para.py defines all the key parameters needed to run a simulation. It controls aspects like computational settings (CPU/GPU), grid resolution, numerical schemes, and data output frequency.

device = 'CPU'                     # 'CPU' or 'GPU' depending on device

device_rank = 0                    # Rank of GPU device if 'GPU' is selected

kind = 'HYDRO'                     # Type of simulation (e.g., 'HYDRO' for hydrodynamics)

INPUT_SET_CASE = True              # Whether to use a predefined case or custom initial conditions
input_case = 'custom'              # Name of the input case if INPUT_SET_CASE is True

dimension = 2                      # Number of spatial dimensions

Nx = 512                           # Number of grid points in the x, y or z direction
Ny = 1
Nz = 512

BOX_SIZE_DEFAULT = True            # Whether to use the default box size

nu = 2E-2                          # Kinematic viscosity

FORCING_ENABLED = False            # Whether external forcing is enabled

time_scheme = 'RK4'                # Time integration scheme (e.g., 'RK4' for Runge-Kutta 4th order)

t_initial = 0                      # Initial time
t_final = 10                       # Final time
dt = 1E-3                          # Time step size

FIXED_DT = True                    # Whether to use a fixed time step size

PRINT_PARAMETERS = True            # Whether to print simulation parameters

iter_field_save_start = t_initial  # Iteration to start saving field data
iter_field_save_inter = 100        # Interval between saving field data

iter_glob_energy_print_start = t_initial # Iteration to start printing global energy
iter_glob_energy_print_inter = 1         # Interval between printing global energy

iter_ekTk_save_start = t_initial   # Iteration to start saving kinetic and thermal energy
iter_ekTk_save_inter = 100         # Interval between saving kinetic and thermal energy

iter_modes_save_start = t_initial  # Iteration to start saving mode data
iter_modes_save_inter = 1000       # Interval between saving mode data

Running the code#

To execute the solver, simply run the tarang_cli.py script:

python3 tarang_cli.py

Note: All commands have to be run from the root directory of the solver bundle i.e. from the same directory as para.py or tarang_cli.py.

This will produce an output similar to the following:

TARANG

Running SEQUENTIAL SOLVER on CPU at rank 0 with PID 5323
Output path = path/to/output

Dimension = 2
Grid resolution = [512, 1, 512]
Box size = [6.283185307179586, 6.283185307179586, 6.283185307179586]

Time scheme = RK4
t_initial = 0
t_final = 10
dt = 0.001

Modes probe = [(1, 0)]



Problem kind is HYDRO

Active viscous dissipation = ['(0.02)k^{2}']

No external forcing: Decaying simulation


t dt Eu div_u eps_u
0 0.001 2.0 0.0 0.08
0.001 0.001 1.999920001599979 3.6995906119510824e-32 0.07999680006399916
.
.
.
9.999 0.001 1.3406937187474521 1.725685891514344e-31 0.053627748749898084
10.0 0.001 1.3406400920712431 1.6640580836512109e-31 0.05362560368284973

Compute time = 1067.868339061737

Time per step = 0.1067868339061737

Output Structure#

If the same parameters were used, the output directory will contain the following structure:

output/
├── ekTk.h5                # Energy spectrum data
├── fields/                # Solution snapshots
│   ├── Soln_0.000000.h5
│   ├── Soln_0.100000.h5
│   ├── ...
│   └── Soln_10.000000.h5
├── glob.h5                # Global diagnostics data like energy, dissipation rate
├── modes.h5               # Mode-specific time evolution
├── para.py                # Parameter file
├── paraIO.py              # Input/output configuration
├── t_dt.h5                # Time step evolution
└── t_field_save.h5        # Field saving time data

Soln_X.XXXXXX.h5 (Field Snapshots)#

Captures the state of the velocity field at different time steps during the simulation.

Soln_X.XXXXXX.h5
├Vkx    [(r: float64, i: float64): 512 × 257]    # X-component of the Velocity Fourier field
└Vkz    [(r: float64, i: float64): 512 × 257]    # Z-component of the Velocity Fourier field

ekTk.h5 (Energy Spectrum Data)#

Contains the evolution of kinetic energy (ek) and transfer functions (Tk) over time.

ekTk.h5
├Tk     [float64: 101 × 364 × 2]    # Transfer function at different time steps
├ek     [float64: 101 × 364 × 2]    # Energy spectrum values
├k      [float64: 364]              # Wavenumber array
└t      [float64: 101]              # Time instances corresponding to stored values

glob.h5 (Global Diagnostics)#

Stores integral quantities describing the overall evolution of the flow.

glob.h5
├ Eu                [float64: 10001] # Total kinetic energy over time
├ Eu_dissipation    [float64: 10001] # Energy dissipation rate
├ div_v             [float64: 10001] # Divergence of velocity field
└ t                 [float64: 10001] # Time array

modes.h5 (Mode Evolution)#

Tracks the evolution of selected Fourier modes over time.

modes.h5
├modes_Vx       [(r: float64, i: float64): 11 × 1]  # X-component mode values (real & imaginary)
├modes_Vz       [(r: float64, i: float64): 11 × 1]  # Z-component mode values (real & imaginary)
└t              [float64: 11]

t_dt.h5 (Time Step Evolution)#

Stores the time step (dt) used during the simulation.

t_dt.h5
├ dt      [float64: 10000] # Time step values at different iterations
└ t       [float64: 10000] # Corresponding time array

t_field_save.h5 (Field Saving Times)#

Records the time instances at which field snapshots were saved.

t_field_save.h5
└t      [float64: 101]  # Time steps when solution snapshots were stored

Post-processing#

To generate post-processing plots, run the post_proc/post_proc.py script while specifying the required plot type in command line arguments:

python3 post_proc/post_proc.py '<output_plot_dir>' '<t_initial> <t_final>' spectrum energy flux field
  • '<output_plot_dir>': The directory where the generated plots will be saved.

  • '<t_initial> <t_final>': The initial and final time for averaged plots. If both are equal plot will be made for a single frame.

  • spectrum: Generates a spectrum plot.

  • energy: Generates an energy plot.

  • flux: Generates a flux plot.

  • field: Generates a field quiver plot.

Note: Do not forget the quotation marks for output directory and the time entries.

Running this script should give the following plots displayed and stored in output/plots folder for $To generate post-processing plots, run the post_proc/post_proc.py script while specifying the required plot type in command line arguments:

python3 post_proc/post_proc.py '<output_plot_dir>' '<t_initial> <t_final>' spectrum energy flux field
  • '<output_plot_dir>': The directory where the generated plots will be saved.

  • '<t_initial> <t_final>': The initial and final time for averaged plots. If both are equal plot will be made for a single frame.

  • spectrum: Generates a spectrum plot.

  • energy: Generates an energy plot.

  • flux: Generates a flux plot.

  • field: Generates a field quiver plot.

Note: Do not forget the quotation marks for output directory and the time entries.

Running this script should give the following plots displayed and stored in output/plots folder for $T = 10$:

Time series energy plot#

Time series energy plot

Spectrum plot at T=10#

Spectrum plot at T=10

Flux plot at T=10#

Flux plot at T=10

Field snapshot at T=10#

Field plot at T=10