Writing a file

This example demonstrates how to create and write data to an ExodusII file.

Creating a file

To create a new ExodusII file, create a File object with FileAccess::WRITE:

#include "exodusIIcpp/exodusIIcpp.h"

using namespace exodusIIcpp;

// Create a new file
File file("output.e", FileAccess::WRITE);

Initializing the file structure

Before writing any data, you must initialize the file with mesh dimensions and counts. This defines the overall structure of the mesh:

// Initialize file with:
// - title: descriptive name
// - num_dims: spatial dimension (1, 2, or 3)
// - num_nodes: total number of nodes
// - num_elems: total number of elements
// - num_elem_blks: number of element blocks
// - num_node_sets: number of node sets
// - num_side_sets: number of side sets
file.init("My Mesh",
          3,      // 3D
          10,     // 10 nodes
          5,      // 5 elements
          2,      // 2 element blocks
          1,      // 1 node set
          0);     // 0 side sets

Writing coordinates

Write node coordinates to the file. The number of coordinates must match the number of nodes specified in init():

// For 1D meshes
std::vector<double> x = { 0.0, 1.0, 2.0, 3.0, 4.0 };
file.write_coords(x);

// For 2D meshes
std::vector<double> x = { 0.0, 1.0, 0.0, 1.0, 0.5 };
std::vector<double> y = { 0.0, 0.0, 1.0, 1.0, 0.5 };
file.write_coords(x, y);

// For 3D meshes
std::vector<double> x = { 0.0, 1.0, 0.0, 1.0, 0.5 };
std::vector<double> y = { 0.0, 0.0, 1.0, 1.0, 0.5 };
std::vector<double> z = { 0.0, 0.0, 0.0, 0.0, 1.0 };
file.write_coords(x, y, z);

// Write coordinate names (optional)
file.write_coord_names();

Writing element blocks

Define and write element blocks. Each block contains elements of the same type:

// Connectivity for block 1: 2 TRI3 elements
// Triangle 1: nodes 1, 2, 5
// Triangle 2: nodes 2, 3, 5
std::vector<int> connect1 = { 1, 2, 5, 2, 3, 5 };
file.write_block(1,         // block ID
                 "TRI3",    // element type
                 2,         // number of elements
                 connect1);

// Connectivity for block 2: 2 QUAD4 elements
// Quad 1: nodes 1, 2, 4, ?
// Quad 2: nodes 2, 3, 4, ?
std::vector<int> connect2 = { 1, 2, 4, 5, 2, 3, 4, 5 };
file.write_block(2,
                 "QUAD4",
                 2,
                 connect2);

// Write block names (optional)
std::vector<std::string> block_names = { "Triangles", "Quads" };
file.write_block_names(block_names);

Writing node sets

Define node sets (groups of nodes):

// Node set 1: nodes 1 and 2
std::vector<int> node_set_1 = { 1, 2 };
file.write_node_set(1, node_set_1);

// Write node set names (optional)
std::vector<std::string> node_set_names = { "Left Edge" };
file.write_node_set_names(node_set_names);

Writing side sets

Define side sets (groups of element sides):

// Side set 1: side 1 of element 1, side 2 of element 2
std::vector<int> elem_list = { 1, 2 };
std::vector<int> side_list = { 1, 2 };
file.write_side_set(1, elem_list, side_list);

// Write side set names (optional)
std::vector<std::string> side_set_names = { "Bottom Edge" };
file.write_side_set_names(side_set_names);

Writing information records

Add metadata information records:

std::vector<std::string> info = {
    "Generated by my simulation",
    "Date: 2024-01-01",
    "Author: John Doe"
};
file.write_info(info);

Writing time steps and variables

To write time-dependent data, define variable names and write values for each time step:

// Define time step 1 at time 0.0
file.write_time(1, 0.0);

// Write nodal variable names
std::vector<std::string> nodal_var_names = { "Displacement", "Velocity" };
file.write_nodal_var_names(nodal_var_names);

// Write nodal variable values for time step 1
// Variable 1 (Displacement) values for all nodes
std::vector<double> displacement = { 0.0, 0.1, 0.2, 0.15, 0.05 };
file.write_nodal_var(1,      // time step
                     1,      // variable index
                     displacement);

// Variable 2 (Velocity) values for all nodes
std::vector<double> velocity = { 0.0, 1.0, 2.0, 1.5, 0.5 };
file.write_nodal_var(1, 2, velocity);

// Write elemental variable names
std::vector<std::string> elem_var_names = { "Stress" };
file.write_elem_var_names(elem_var_names);

// Write elemental variable values for block 1
std::vector<double> stress_block1 = { 100.0, 150.0 };
file.write_elemental_variable_values(1,      // time step
                                    1,       // variable index
                                    1,       // block ID
                                    stress_block1);

// Write global variables
std::vector<std::string> global_var_names = { "Total Energy" };
file.write_global_var_names(global_var_names);

// Write global variable value for time step 1
file.write_global_var(1,    // time step
                      1,    // variable index
                      1000.0);  // value

Writing additional time steps

To write more time steps, repeat the process:

// Time step 2
file.write_time(2, 1.0);

std::vector<double> displacement_t2 = { 0.1, 0.2, 0.4, 0.3, 0.1 };
file.write_nodal_var(2, 1, displacement_t2);

std::vector<double> velocity_t2 = { 1.0, 2.0, 4.0, 3.0, 1.0 };
file.write_nodal_var(2, 2, velocity_t2);

std::vector<double> stress_block1_t2 = { 200.0, 250.0 };
file.write_elemental_variable_values(2, 1, 1, stress_block1_t2);

file.write_global_var(2, 1, 2000.0);

Partial writes

For very large files, you can write variables in parts rather than all at once:

// Write nodal variable values node by node
for (int i = 0; i < num_nodes; ++i) {
    file.write_partial_nodal_var(time_step,    // time step
                                 var_index,    // variable index
                                 block_id,     // block ID
                                 i + 1,        // node index (1-based)
                                 values[i]);   // value
}

// Write elemental variable values element by element
for (int i = 0; i < num_elements; ++i) {
    file.write_partial_elem_var(time_step,    // time step
                                var_index,    // variable index
                                block_id,     // block ID
                                i + 1,        // element index (1-based)
                                elem_values[i]);  // value
}

Updating and closing

After writing all data for a time step, call update() to finalize the data:

// Update after writing all data for this time step
file.update();

Close the file when done:

// Close the file explicitly
file.close();

// Or let it close automatically when the File object goes out of scope

Appending to an existing file

To add new time steps to an existing file, use FileAccess::APPEND:

// Open existing file for appending
File file("output.e", FileAccess::APPEND);

// Read existing time steps to determine the next time step number
file.read_times();
int next_time_step = file.get_num_times() + 1;

// Write new time step data
file.write_time(next_time_step, 2.0);
file.write_nodal_var(next_time_step, 1, new_displacement);
file.update();
file.close();

Complete example

Here’s a complete example that creates a simple 2D mesh with time-dependent data:

#include "exodusIIcpp/exodusIIcpp.h"
#include <iostream>

using namespace exodusIIcpp;

int main()
{
    // Create file
    File file("simple.e", FileAccess::WRITE);

    // Initialize: 2D mesh, 4 nodes, 1 quad element, 1 block, no sets
    file.init("Simple Quad", 2, 4, 1, 1, 0, 0);

    // Write coordinates
    std::vector<double> x = { 0.0, 1.0, 1.0, 0.0 };
    std::vector<double> y = { 0.0, 0.0, 1.0, 1.0 };
    file.write_coords(x, y);
    file.write_coord_names();

    // Write element block
    std::vector<int> connect = { 1, 2, 3, 4 };
    file.write_block(1, "QUAD4", 1, connect);
    std::vector<std::string> block_names = { "Material 1" };
    file.write_block_names(block_names);

    // Write time step 1
    file.write_time(1, 0.0);
    std::vector<std::string> var_names = { "Temperature" };
    file.write_nodal_var_names(var_names);
    std::vector<double> temp_t1 = { 100.0, 200.0, 250.0, 150.0 };
    file.write_nodal_var(1, 1, temp_t1);
    file.update();

    // Write time step 2
    file.write_time(2, 1.0);
    std::vector<double> temp_t2 = { 150.0, 250.0, 300.0, 200.0 };
    file.write_nodal_var(2, 1, temp_t2);
    file.update();

    file.close();
    std::cout << "File created successfully!" << std::endl;

    return 0;
}