Skip to content

File Formats

In this section we describe the file formats of all files used by the solver.

Grid File format

LAVACurv uses plot3d grids as the format for specifying the multi-block grids. Since there are nearly unlimited number of formats of plot3d grids, we will be very specific about what constitutes valid input to the solver. The plot3d grids for LAVACurv must use the following format(s):

  • Multiblock
  • Double precision
  • Little-Endian
  • With or Without Iblank Array
  • With or Without Record Markers

That is there are 4 possible formats : With/Without Iblanks and With/Without Record Markers. The solver can distinguish between these 4 grid types and no further information is required. The following fortran code will write a valid grid without record markers and with an iblank array.

! Each of X,Y,Z,ib are of length nZone and are a list
! of variable sized arrays. Eg:
! type listOfArraysR8
!     real(kind=8), dimension(:, :, :), allocatable :: arr
! end type
! type listOfArraysI4
! integer(kind=4), dimension(:, :, :), allocatable :: arr
! end type

type(listOfArraysR8) :: X,Y,Z
type(listOfArraysI4) :: ib

allocate(X(nZone), Y(nZone), Z(nZone), ib(nZone))

! Allocate individual arrays for each zone and set variables

open(newUnit=iUnit, form='unformatted', access='stream')
write(iUnit) nZone ! Number of Zones
write(iUnit) sizes ! Dimensions of (3, nZone)
do i=1, nZone
  write(iUnit) X(i)%arr, Y(i)%arr, Z(i)%arr, ib(i)%arr
end do
close(iUnit)

BC and Subset Files

The BCFile and the optional Subset file are used to define contiguous sections of grid blocks. For the BCFile this is used for specifying boundary conditions. For the subset file, these sections are used for a variety of purposes. These files have the following syntax

!------------------------------------------------------------
! Label     nz     jbeg   jend      kbeg kend      lbeg lend
!------------------------------------------------------------
in          1       1     -1         1     1        1     -1
out         1       1     -1        -1    -1        1     -1
sym         1       1     -1         1    -1       -1     -1
sym         1       1      1         1    -1        1     -1
sym         1      -1     -1         1    -1        1     -1
sym         1       1     -1         1    49        1      1
sym         1       1     -1       129    -1        1      1
wall        1       1     -1        49   129        1      1

All lines that begin with ! are treated as comment lines and ignored. The first entry is the label. This can be any string that is appropriate for the specific problem. The second column is the zone (or grid or block) number the section belong to. The remaining 6 entries (jBeg, jEnd, kBeg, kEnd, lBeg, lEnd) give the start and end ranges for that particular subset. A special negative syntax is allowed: The -1 index refers to the last node of the block. Therefore a range of 1 -1 covers the entire block range no matter what the block size. Note that multiple different tags are allowed on a given surface. In the example above, the L=1 boundary has 3 different (1->49, 49->129 and (129->-1)sections, with two unique labels (sym and wall). The order of line in the BC file does not matter. Additional blank and or comments lines may be added as desired.

B2B Files

The B2B file is used to uniquely describe how two blocks are connected to each other in a multi-block grid. Note that periodic boundary conditions also fall into this category.

! BlkID    js je   ks ke   ls le  DonorID   djs dje  dks dke  dls dle  tx ty tz
     8     1  1    1  -1   1  -1   8        -1  -1   1   -1   1   -1   1  2  3
     8    -1 -1    1  -1   1  -1   8         1   1   1   -1   1   -1   1  2  3

Like the BC and subset files, the ! denotes a comment line. The ordering of the lines do not matter and blank lines are ignored. The first entry is BlkID the index of grid block this connection applies to. The next 6 numbers (js/je/ks/ke/ls/le) are describe the range of the blkID that is connected to another block (or itself in the case of periodic boundary). DonorID is the block that which previously described section is connected to. This can be any block number including itself. The next 6 numbers (djs/dje/dks/dke/dls/dle, the \'d\' means \"donor\" here) are the subset of the donor block that is connected to the first range. Note that depending on how the blocks are oriented, the starting indices may be larger than the end indices. Note that like the BC and subset files, a special \"negative\" index is allowed where -1 denotes the last index of the block. The final 3 numbers describe the \"transform\" which is how the indices of the first block relate to the indices of the second block. See the explanation on the CGNS website for more information: https://cgns.github.io/CGNS_docs_current/sids/cnct.html#Transform

Interp Files

These files are required only when overset meshes are used. The file must be in \"INTOUT\" file type. This file is typically written by LAVACurv itself when performing hole cutting but we describe the format here as well.

open(newunit=iUnit, file="INTOUT", form='unformatted',&
     status='replace')
write(iUnit) nOnBlock

do iBlk=1, nZones
  write(iUnit)  &
      blkIntData(iBlk)%arr(:, 1), & ! j index
      blkIntData(iBlk)%arr(:, 2), & ! k index
      blkIntData(iBlk)%arr(:, 3), & ! l index
      blkIntData(iBlk)%arr(:, 4), & ! donor Block
      blkIntData(iBlk)%arr(:, 5), & ! donor j
      blkIntData(iBlk)%arr(:, 6), & ! donor k
      blkIntData(iBlk)%arr(:, 7), & ! donor l
      blkRealData(iBlk)%arr(:, 1), & ! fracJ
      blkRealData(iBlk)%arr(:, 2), & ! fracK
      blkRealData(iBlk)%arr(:, 3)    ! fracL

  write(iUnit) blkIblank(iBlk)%arr ! iBlank
end do close (iUnit)

The first write is array sized nZones. Each entry contains the number of fringes (or interpolated) points for that block. Then, looping over each zone, we write the jkl indices of the fringe node followed by donor block, lower left-index of the donor cell, and the three fractional weights. Finally, a full iblank array for the zone is written. This iblank array however is not used by the solver and its values do not matter.

Restart Files

These files are written by the solver to restart a previous simulation where it finished. Restart files are used to restart both steady and unsteady simulations. The contents of the restart file depend on the type of simulation being performed: The code automatically determines which variables need to be saved to ensure a seamless restart. When a restart \"file\" is written there are actually 4 files written:

  • a .rst file
  • a .nam file
  • a .info file
  • a .iter file

The .rst is the main file storing the field information. This is a plot3d function file, written in double precision, native endian, without record markers. This file may be loaded into tecplot using the standard Plot3D grid loader.

The .nam is an ascii file that contains the variable names written in the file. A typical .nam file for a steady RANS simulation might look like the following:

Pressure
VelocityX
VelocityY
VelocityZ
Temperature
nut

Note that this file can be loaded into Tecplot to label the variables from the .rst file.

The .info file is ascii file that contains various pieces key-value information required by the solver for seamless restarts. This file should not be modified by the user.

Finally a .iter file stores the iteration-level history of all \"iteration variables\". This file is identical to the data.iter file also written by the code. See dataiterfile{.interpreted-text role="ref"} for more the format of this file.

data.iter File

The data.iter is binary file automatically written by the solver which records non-linear iteration level data during both steady and unsteady simulations. This is a binary file and thus it is not human readable. It can be processed by the plotHist.py routine for performing various post-processing plotting functions.

The format of the file is as follows:

  • a single 32-bit integer, nVar, listing the number of variables
  • a single 32-bit integer, varNameLen, listing the length of each variable name
  • nVar * varNameLen bytes containing the variable names
  • Each subsequent nVar*8 bytes are treated as 64-bit real values corresponding to a single non-linear iteration

The following sample code will read the file using fortran:

module iterLoader
contains
  subroutine loadData(fName, varNames, data)
    use iso_fortran_env
    implicit none
    character(len=*) :: fName
    real(kind=8), dimension(:, :), allocatable :: data
    character(len=:), allocatable, dimension(:) :: varNames
    integer :: fSize, iUnit, nVar, varNameLen, n

    inquire(file=fName, size=fSize)
    fSize = fSize * FILE_STORAGE_SIZE /8 ! Number of bytes

    open(newUnit=iUnit, file=fName, status='old', &
         form='unformatted', access='stream')

    ! Read Header Info
    read(iUnit) nVar
    read(iUnit) varNameLen
    allocate(character(len=varNameLen)::varNames(nVar))
    read(iUnit) varNames

    ! Determine the number of "lines" to read:
    n = (fSize - 8 - nVar*varNameLen) / (nVar*8)
    allocate(data(nVar, n))
    read(iUnit) data
    close(iUnit)
  end subroutine loadData
end module iterLoader

The following sample code will read the file using python:

def loadData(fName):
    import os
    import numpy as np
    fSize = os.path.getsize(fName)
    f = open(fName, 'rb')
    nVar = np.fromfile(f, dtype='i4',count=1)[0]
    strSize = np.fromfile(f, dtype='i4', count=1)[0]
    strs = np.fromfile(f, dtype='c', count=nVar*strSize)
    keys = []
    for i in range(nVar):
        keys.append("".join(strs[i*strSize:(i+1)*strSize]).strip().lower())

    remainingBytes = fSize - 8 - nVar * strSize
    lines = remainingBytes // (nVar * 8)
    buf = np.fromfile(f, dtype=float, count=-1, sep='')
    data = buf[0:lines*nVar].reshape((nVar, lines), order='f')
    f.close()

    return keys, data