Skip to content
Arto Sandroos edited this page Jul 2, 2015 · 12 revisions

VLSV File Format

Table of Contents

Introduction

VLSV file format was created for writing domain-decomposed meshes, and variables defined on their zones, efficiently in parallel using message passing interface (MPI). Here is a list of features:

  • Data written in parallel using collective MPI calls
  • Parallel visualization with VisIt
  • Scalability tested up to tens of millions of zones per mesh
  • Multiple meshes per file
  • Stretched Cartesian, Cylindrical, and Spherical coordinate systems
  • Arbitrary coordinate scaling for visualization purposes (for example, from meters to Earth radii)
  • User-defined axis labels and units

HOWTO: Write a Multi-Domain Mesh

Here is a checklist (for each domain):

  • Separate zones into locals and ghosts. Local zones are always written first, only mesh data needs ghost zones.
  • Figure out an order in which to write out zones.
  • At this point you have local IDs for all zones (=the order they are written to file).
  • Synchronize local IDs with neighbor processes.
  • Each process must know the domain (=MPI rank) where the ghost zone belongs to, and local ID of ghost zone in that domain.

Write Mesh Bounding Box

Write mesh bounding box to array MESH_BBOX (master process only):

long unsigned int bbox[6];
bbox[0] = <<number of blocks in x-direction>>;
bbox[1] = <<number of blocks in y-direction>>;
bbox[2] = <<number of blocks in z-direction>>;
bbox[3] = <<number of cells in x-direction in blocks>>;
bbox[4] = <<number of cells in y-direction in blocks>>;
bbox[5] = <<number of cells in z-direction in blocks>>;

// NOTE: If you are not using block-based mesh, use
//bbox[0] = <<number of zones in x-direction>>;
//bbox[1] = <<number of zones in y-direction>>;
//bbox[2] = <<number of zones in z-direction>>;
//bbox[3] = 1;
//bbox[4] = 1;
//bbox[5] = 1;

map<string,string> xmlAttributes;
xmlAttributes["mesh"] = <<name of your mesh>>;
bool success;
if (myRank == masterRank) success = vlsv.writeArray("MESH_BBOX",xmlAttributes,6,1,bbox);
else success = vlsv.writeArray("MESH_BBOX",xmlAttributes,0,1,bbox);

Following XML attributes are supported:

Attribute name Mandatory or optional? Accepted values Value datatype
mesh Mandatory Name of the mesh string

Rationale: Plugin needs to know how to compute zone (i,j,k) indices from global IDs using the formula given above. Nx is equal to bbox[0]*bbox[3] etc.

Write Bounding Box Node Coordinates

Write bounding box node (x,y,z) coordinates to arrays MESH_NODE_CRDS_X, MESH_NODE_CRDS_Y, and MESH_NODE_CRDS_Z (master process only). NOTE that a mesh always has more nodes than zones:

unsigned int xCells = <<number of zones in x-direction>>;
unsigned int yCells = <<number of zones in y-direction>>;
unsigned int zCells = <<number of zones in z-direction>>;

float* xNodeCrds = new float[xCells+1];
float* yNodeCrds = new float[yCells+1];
float* zNodeCrds = new float[zCells+1];
for (unsigned int i=0; i<xCells+1; ++i) xNodeCrds[i] = <<x-coordinate of node i>>;
for (unsigned int j=0; j<yCells+1; ++j) yNodeCrds[j] = <<y-coordinate of node j>>;
for (unsigned int k=0; k<zCells+1; ++k) zNodeCrds[k] = <<z-coordinate of node k>>;

map<string,string> xmlAttributes;
xmlAttributes["mesh"] = <<name of your mesh>>;
bool success = true;
if (myRank == masterRank) {
   if (vlsv.writeArray("MESH_NODE_CRDS_X",xmlAttributes,xCells+1,1,xNodeCrds) == false) success = false;
   if (vlsv.writeArray("MESH_NODE_CRDS_Y",xmlAttributes,yCells+1,1,yNodeCrds) == false) success = false;
   if (vlsv.writeArray("MESH_NODE_CRDS_Z",xmlAttributes,zCells+1,1,zNodeCrds) == false) success = false;
} else {
   if (vlsv.writeArray("MESH_NODE_CRDS_X",xmlAttributes,0,1,xNodeCrds) == false) success = false;
   if (vlsv.writeArray("MESH_NODE_CRDS_Y",xmlAttributes,0,1,yNodeCrds) == false) success = false;
   if (vlsv.writeArray("MESH_NODE_CRDS_Z",xmlAttributes,0,1,zNodeCrds) == false) success = false;
}

Following XML attributes are supported:

| Attribute name | Mandatory or optional? | Accepted values | Value datatype | | mesh | mandatory | Name of the mesh | string |

Rationale: Plugin calculates zone's (i,j,k) indices from its global ID using the formula given above. Each zone has eight nodes: (i,j,k), (i+1,j,k), (i+1,j+1,k), ..., (i+1,j+1,k+1). Node (x,y,z) coordinates are obtained by indexing the arrays written above.

Write Zone Global ID numbers

Write global IDs of local zones, followed by global IDs of ghost zones, to an array MESH.

unsigned int localID=0;
vector<unsigned int> globalIDs;
for all local zones z {
   // Current value of localID is the local ID of zone z
   unsigned int gID = <<global ID of z>>;
   globalIDs.push_back(gID);
   ++localID;
}
for all ghost zones g {
   // Current value of localID is the local ID of zone g
   unsigned int gID = <<global ID of g>>;
   globalIDs.push_back(gID);
   ++localID;
}
unsigned int N_zones = globalIDs.size();

map<string,string> xmlAttributes;
attributes["name"] = <<name of your mesh>>;
attributes["type"] = "multi_ucd";
bool success = vlsv.writeArray("MESH",xmlAttributes,N_zones,1,&(globalIDs[0]));

The example above also shows how local ID values are obtaines -- it is simply zone's order in vector globalIDs. Local IDs need to be syncronized between neighboring MPI processes, they are needed in writing array MESH_GHOST_LOCALIDS below. Important: the order of zones in vector globalIDs defines the order in which a process writes out its variable data.

Following XML attributes are supported:

| Attribute name | Mandatory or optional? | Accepted values | value datatype | | domains | optional | number of domains | integer |

Rationale: In order for VisIt to visualize data in parallel it must be able to compute each domain independently, including ghost zones. Plugin uses global IDs to compute node coordinates of each zone.

Write Domain Sizes

Write a vector of size two containing (total number of zones, number of ghosts) in the domain to an array MESH_DOMAIN_SIZES:

int domainSize[2];
domainSize[0] = <<total number or zones in this domain>>;
domainSize[1] = <<number of ghost zones in this domain>>;

map<string,string> xmlAttributes;
attributes["mesh"] = <<name of mesh>>;bool success = vlsv.writeArray("MESH_DOMAIN_SIZES",xmlAttributes,1,2,domainSize);

Following XML attributes are supported:

| Attribute name | Mandatory or optional? | Accepted values | Value datatype | | mesh | mandatory | Name of the mesh | string |

Rationale: Plugin needs to know the number of local and ghost zones in each domain -- ghost zones need to be flagged so that VisIt does not draw them. Number of ghost zones given here also tells how to index the two arrays written below.

Write Ghost Zone Domain and Local ID Numbers

Write ghost zone domain IDs to array MESH_GHOST_DOMAINS, and local IDs to array MESH_GHOST_LOCALIDS:

unsigned int N_ghosts = 0;
vector<unsigned int> ghostDomainIDs;
vector<unsigned int> ghostLocalIDs;
for all ghost zones g {
   int domainID = <<MPI process rank owning ghost zone g>>;
   int localID = <<local ID of ghost zone g in domain domainID>>;
   ghostDomainIDs.push_back(domainID);
   ghostLocalIDs.push_back(localID);
   ++N_ghosts;
}

map<string,string> xmlAttributes;
attributes["mesh"] = <name of mesh>;
bool success1 = vlsv.writeArray("MESH_GHOST_DOMAINS",xmlAttributes,N_ghosts,1,&(ghostDomainIDs[0]));
bool success2 = vlsv.writeArray("MESH_GHOST_LOCALIDS",xmlAttributes,N_ghosts,1,&(ghostLocalIDs[0]));

Following XML attributes are supported:

| Attribute name | Mandatory or optional? | Accepted values | Value datatype | | mesh | mandatory | Name of the mesh | string |

HOWTO: Write Multi-Domain Variables

VLSV file format accepts all types of variables. Variables are defined as tuples that exist of all zones in the domain. VisIt, however, only supports scalars (tuple size 1), vectors (tuple size 2 or 3), and tensors (tuple size 9). Variable data must be written in the same order as zones were written to array MESH above. Variables are written to arrays called VARIABLE. Example below shows how to write a three-component vector variable to VLSV file:

// Copy variable data to temporary buffer:
int arraySize=<<number of local zones in domain>>;
int vectorSize=3;
double* buffer = new double[arraySize*vectorSize];
int localID=0;
for all local zones z {
   for (i=0; i<vectorSize; ++i) {
      buffer[localID*vectorSize+i] = <<value of i:th component of vector in zone z>>
   }
   ++localID;
}

// Write buffer to file:
map<string,string> xmlAttributes;
xmlAttributes["mesh"]=<<name of your variable>>;
xmlAttributes["mesh"]=<<name of your mesh>>;
bool success=vlsv.writeArray("VARIABLE",xmlAttributes,arraySize,vectorSize,buffer);
delete [] buffer;

Rationale: each domain only writes variable data on its local zones. Plugin uses MESH_GHOST_DOMAINS and MESH_GHOST_LOCALIDS arrays to fetch values to domain's ghost zones.

Following XML attributes are supported:

Clone this wiki locally