Program Listing for File mesh.cpp

Return to documentation for file (src/mesh/mesh.cpp)

#include "mesh.hpp"

#include <fstream>
#include <iomanip>

#include "hdf5.h"
#include "output.hpp"

namespace lili::mesh {
void PrintMeshSize(const MeshSize& mesh_size, lili::output::LiliCout& lout) {
  lout << "=========== Mesh information ===========" << std::endl;
  lout << "dim           = " << mesh_size.dim << std::endl;
  lout << "n             = (" << mesh_size.nx << ", " << mesh_size.ny << ", "
       << mesh_size.nz << ")" << std::endl;
  lout << "ng            = (" << mesh_size.ngx << ", " << mesh_size.ngy << ", "
       << mesh_size.ngz << ")" << std::endl;
  lout << "l             = (" << mesh_size.lx << ", " << mesh_size.ly << ", "
       << mesh_size.lz << ")" << std::endl;
  lout << "r0            = (" << mesh_size.x0 << ", " << mesh_size.y0 << ", "
       << mesh_size.z0 << ")" << std::endl;
}

void UpdateMeshSizeDim(MeshSize& mesh_size) {
  mesh_size.dim = (mesh_size.nz > 1) ? 3 : ((mesh_size.ny > 1) ? 2 : 1);
}

void SaveMesh(Mesh<double>& mesh, const char* file_name, const char* data_name,
              bool include_ghost) {
  // Check if file exists
  hid_t file_id;
  std::ifstream fs(file_name);
  bool file_exists = fs.good();
  if (file_exists) {
    file_exists = H5Fis_hdf5(file_name) > 0;
  }

  if (file_exists) {
    file_id = H5Fopen(file_name, H5F_ACC_RDWR, H5P_DEFAULT);
  } else {
    file_id = H5Fcreate(file_name, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
  }

  // Create dataspace with mesh size as the final size
  int nx, ny, nz;
  int ixoff, iyoff, izoff;
  if (include_ghost) {
    nx = mesh.nx() + 2 * mesh.ngx();
    ny = mesh.ny() + 2 * mesh.ngy();
    nz = mesh.nz() + 2 * mesh.ngz();

    ixoff = -mesh.ngx();
    iyoff = -mesh.ngy();
    izoff = -mesh.ngz();
  } else {
    nx = mesh.nx();
    ny = mesh.ny();
    nz = mesh.nz();

    ixoff = 0;
    iyoff = 0;
    izoff = 0;
  }

  hsize_t dims[3] = {static_cast<hsize_t>(nx), static_cast<hsize_t>(ny),
                     static_cast<hsize_t>(nz)};
  hid_t dataspace_id = H5Screate_simple(3, dims, NULL);

  // Create dataset
  if (file_exists && H5Lexists(file_id, data_name, H5P_DEFAULT) > 0) {
    H5Ldelete(file_id, data_name, H5P_DEFAULT);
  }
  hid_t dataset_id =
      H5Dcreate(file_id, data_name, H5T_NATIVE_DOUBLE, dataspace_id,
                H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);

  // Prepare data to be written transpose it to row-major order
  double* data;

  data = new double[nx * ny * nz]();
  for (int i = 0; i < nx; ++i) {
    for (int j = 0; j < ny; ++j) {
      for (int k = 0; k < nz; ++k) {
        data[i * ny * nz + j * nz + k] = mesh(i + ixoff, j + iyoff, k + izoff);
      }
    }
  }

  // Write data
  H5Dwrite(dataset_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, data);

  // Close dataset and dataspace
  H5Dclose(dataset_id);
  H5Sclose(dataspace_id);

  // Close file
  H5Fclose(file_id);

  // Free memory
  delete[] data;
}

void LoadMeshTo(Mesh<double>& mesh, const char* file_name,
                const char* data_name, bool include_ghost) {
  // Check if file exists
  hid_t file_id;
  std::ifstream fs(file_name);
  bool file_exists = fs.good();
  if (file_exists) {
    file_exists = H5Fis_hdf5(file_name) > 0;
  }

  if (file_exists) {
    file_id = H5Fopen(file_name, H5F_ACC_RDWR, H5P_DEFAULT);
  } else {
    std::cerr << "File " << file_name << " does not exist..." << std::endl;
    exit(2);
  }

  // Check if dataset exists
  if (H5Lexists(file_id, data_name, H5P_DEFAULT) <= 0) {
    std::cerr << "Dataset " << data_name << " does not exist..." << std::endl;
    exit(2);
  }

  // Open dataset
  hid_t dataset_id = H5Dopen(file_id, data_name, H5P_DEFAULT);

  // Get dataset size
  hid_t dataspace_id = H5Dget_space(dataset_id);
  const int ndims = H5Sget_simple_extent_ndims(dataspace_id);
  hsize_t dims[ndims];
  H5Sget_simple_extent_dims(dataspace_id, dims, NULL);

  // Resize mesh if needed
  int ndx = dims[0];
  int ndy = ndims > 1 ? dims[1] : 1;
  int ndz = ndims > 2 ? dims[2] : 1;
  int ngx = mesh.ngx();
  int ngy = mesh.ngy();
  int ngz = mesh.ngz();

  if (include_ghost) {
    mesh.Resize(ndx - 2 * ngx, ndy - 2 * ngy, ndz - 2 * ngz, ngx, ngy, ngz);
  } else {
    mesh.Resize(ndx, ndy, ndz, ngx, ngy, ngz);
  }

  // Read data
  double* data = new double[ndx * ndy * ndz]();
  H5Dread(dataset_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, data);

  // Copy data to mesh
  int ixoff, iyoff, izoff;
  if (include_ghost) {
    ixoff = -ngx;
    iyoff = -ngy;
    izoff = -ngz;
  } else {
    ixoff = 0;
    iyoff = 0;
    izoff = 0;
  }

  for (int i = 0; i < ndx; ++i) {
    for (int j = 0; j < ndy; ++j) {
      for (int k = 0; k < ndz; ++k) {
        mesh(i + ixoff, j + iyoff, k + izoff) =
            data[i * ndy * ndz + j * ndz + k];
      }
    }
  }

  // Close dataset and dataspace
  H5Dclose(dataset_id);
  H5Sclose(dataspace_id);

  // Close file
  H5Fclose(file_id);

  // Clean up
  delete[] data;
}
}  // namespace lili::mesh