This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/extern/mantaflow/preprocessed/fileio/iogrids.cpp
Sebastián Barschkis 0cdc75ccd2 Fluid: Cleanup build system for extern mantaflow
No longer including unused dependencies. Should numpy IO be needed at some point, the Manta source update script can be configured so that the required dependencies are included again.
2020-07-17 15:58:13 +02:00

1454 lines
46 KiB
C++

// DO NOT EDIT !
// This file is generated using the MantaFlow preprocessor (prep generate).
/******************************************************************************
*
* MantaFlow fluid solver framework
* Copyright 2011-2016 Tobias Pfaff, Nils Thuerey
*
* This program is free software, distributed under the terms of the
* Apache License, Version 2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Loading and writing grids and meshes to disk
*
******************************************************************************/
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <cstring>
#if NO_ZLIB != 1
extern "C" {
# include <zlib.h>
}
#endif
#if NO_CNPY != 1
# include "cnpy.h"
#endif
#include "mantaio.h"
#include "grid.h"
#include "vector4d.h"
#include "grid4d.h"
using namespace std;
namespace Manta {
static const int STR_LEN_GRID = 252;
//! uni file header, v4
typedef struct {
int dimX, dimY, dimZ; // grid size
int gridType, elementType, bytesPerElement; // data type info
char info[STR_LEN_GRID]; // mantaflow build information
int dimT; // optionally store forth dimension for 4d grids
unsigned long long timestamp; // creation time
} UniHeader;
// note: header v4 only uses 4 bytes of the info string to store the fourth dimension, not needed
// for pdata
//*****************************************************************************
// conversion functions for double precision
// (note - uni files always store single prec. values)
//*****************************************************************************
#if NO_ZLIB != 1
template<class GRIDT> void gridConvertWrite(gzFile &gzf, GRIDT &grid, void *ptr, UniHeader &head)
{
errMsg("gridConvertWrite: unknown type, not yet supported");
}
template<> void gridConvertWrite(gzFile &gzf, Grid<int> &grid, void *ptr, UniHeader &head)
{
gzwrite(gzf, &head, sizeof(UniHeader));
gzwrite(gzf, &grid[0], sizeof(int) * head.dimX * head.dimY * head.dimZ);
}
template<> void gridConvertWrite(gzFile &gzf, Grid<double> &grid, void *ptr, UniHeader &head)
{
head.bytesPerElement = sizeof(float);
gzwrite(gzf, &head, sizeof(UniHeader));
float *ptrf = (float *)ptr;
for (int i = 0; i < grid.getSizeX() * grid.getSizeY() * grid.getSizeZ(); ++i, ++ptrf) {
*ptrf = (float)grid[i];
}
gzwrite(gzf, ptr, sizeof(float) * head.dimX * head.dimY * head.dimZ);
}
template<>
void gridConvertWrite(gzFile &gzf, Grid<Vector3D<double>> &grid, void *ptr, UniHeader &head)
{
head.bytesPerElement = sizeof(Vector3D<float>);
gzwrite(gzf, &head, sizeof(UniHeader));
float *ptrf = (float *)ptr;
for (int i = 0; i < grid.getSizeX() * grid.getSizeY() * grid.getSizeZ(); ++i) {
for (int c = 0; c < 3; ++c) {
*ptrf = (float)grid[i][c];
ptrf++;
}
}
gzwrite(gzf, ptr, sizeof(Vector3D<float>) * head.dimX * head.dimY * head.dimZ);
}
template<> void gridConvertWrite(gzFile &gzf, Grid4d<int> &grid, void *ptr, UniHeader &head)
{
gzwrite(gzf, &head, sizeof(UniHeader));
gzwrite(gzf, &grid[0], sizeof(int) * head.dimX * head.dimY * head.dimZ * head.dimT);
}
template<> void gridConvertWrite(gzFile &gzf, Grid4d<double> &grid, void *ptr, UniHeader &head)
{
head.bytesPerElement = sizeof(float);
gzwrite(gzf, &head, sizeof(UniHeader));
float *ptrf = (float *)ptr;
IndexInt s = grid.getStrideT() * grid.getSizeT();
for (IndexInt i = 0; i < s; ++i, ++ptrf) {
*ptrf = (float)grid[i];
}
gzwrite(gzf, ptr, sizeof(float) * s);
}
template<>
void gridConvertWrite(gzFile &gzf, Grid4d<Vector3D<double>> &grid, void *ptr, UniHeader &head)
{
head.bytesPerElement = sizeof(Vector3D<float>);
gzwrite(gzf, &head, sizeof(UniHeader));
float *ptrf = (float *)ptr;
IndexInt s = grid.getStrideT() * grid.getSizeT();
for (IndexInt i = 0; i < s; ++i) {
for (int c = 0; c < 3; ++c) {
*ptrf = (float)grid[i][c];
ptrf++;
}
}
gzwrite(gzf, ptr, sizeof(Vector3D<float>) * s);
}
template<>
void gridConvertWrite(gzFile &gzf, Grid4d<Vector4D<double>> &grid, void *ptr, UniHeader &head)
{
head.bytesPerElement = sizeof(Vector4D<float>);
gzwrite(gzf, &head, sizeof(UniHeader));
float *ptrf = (float *)ptr;
IndexInt s = grid.getStrideT() * grid.getSizeT();
for (IndexInt i = 0; i < s; ++i) {
for (int c = 0; c < 4; ++c) {
*ptrf = (float)grid[i][c];
ptrf++;
}
}
gzwrite(gzf, ptr, sizeof(Vector4D<float>) * s);
}
template<class T> void gridReadConvert(gzFile &gzf, Grid<T> &grid, void *ptr, int bytesPerElement)
{
errMsg("gridReadConvert: unknown type, not yet supported");
}
template<> void gridReadConvert<int>(gzFile &gzf, Grid<int> &grid, void *ptr, int bytesPerElement)
{
gzread(gzf, ptr, sizeof(int) * grid.getSizeX() * grid.getSizeY() * grid.getSizeZ());
assertMsg(bytesPerElement == sizeof(int),
"grid element size doesn't match " << bytesPerElement << " vs " << sizeof(int));
// easy, nothing to do for ints
memcpy(&(grid[0]), ptr, sizeof(int) * grid.getSizeX() * grid.getSizeY() * grid.getSizeZ());
}
template<>
void gridReadConvert<double>(gzFile &gzf, Grid<double> &grid, void *ptr, int bytesPerElement)
{
gzread(gzf, ptr, sizeof(float) * grid.getSizeX() * grid.getSizeY() * grid.getSizeZ());
assertMsg(bytesPerElement == sizeof(float),
"grid element size doesn't match " << bytesPerElement << " vs " << sizeof(float));
float *ptrf = (float *)ptr;
for (int i = 0; i < grid.getSizeX() * grid.getSizeY() * grid.getSizeZ(); ++i, ++ptrf) {
grid[i] = (double)(*ptrf);
}
}
template<>
void gridReadConvert<Vec3>(gzFile &gzf, Grid<Vec3> &grid, void *ptr, int bytesPerElement)
{
gzread(gzf, ptr, sizeof(Vector3D<float>) * grid.getSizeX() * grid.getSizeY() * grid.getSizeZ());
assertMsg(bytesPerElement == sizeof(Vector3D<float>),
"grid element size doesn't match " << bytesPerElement << " vs "
<< sizeof(Vector3D<float>));
float *ptrf = (float *)ptr;
for (int i = 0; i < grid.getSizeX() * grid.getSizeY() * grid.getSizeZ(); ++i) {
Vec3 v;
for (int c = 0; c < 3; ++c) {
v[c] = double(*ptrf);
ptrf++;
}
grid[i] = v;
}
}
template<class T>
void gridReadConvert4d(gzFile &gzf, Grid4d<T> &grid, void *ptr, int bytesPerElement, int t)
{
errMsg("gridReadConvert4d: unknown type, not yet supported");
}
template<>
void gridReadConvert4d<int>(gzFile &gzf, Grid4d<int> &grid, void *ptr, int bytesPerElement, int t)
{
gzread(gzf, ptr, sizeof(int) * grid.getSizeX() * grid.getSizeY() * grid.getSizeZ());
assertMsg(bytesPerElement == sizeof(int),
"grid element size doesn't match " << bytesPerElement << " vs " << sizeof(int));
// nothing to do for ints
memcpy(&(grid[grid.getSizeX() * grid.getSizeY() * grid.getSizeZ() * t]),
ptr,
sizeof(int) * grid.getSizeX() * grid.getSizeY() * grid.getSizeZ());
}
template<>
void gridReadConvert4d<double>(
gzFile &gzf, Grid4d<double> &grid, void *ptr, int bytesPerElement, int t)
{
assertMsg(bytesPerElement == sizeof(float),
"grid element size doesn't match " << bytesPerElement << " vs " << sizeof(float));
float *ptrf = (float *)ptr;
gzread(gzf, ptr, sizeof(float) * grid.getSizeX() * grid.getSizeY() * grid.getSizeZ());
for (IndexInt i = 0; i < grid.getSizeX() * grid.getSizeY() * grid.getSizeZ(); ++i, ++ptrf) {
grid[grid.getSizeX() * grid.getSizeY() * grid.getSizeZ() * t + i] = (double)(*ptrf);
}
}
template<>
void gridReadConvert4d<Vec3>(
gzFile &gzf, Grid4d<Vec3> &grid, void *ptr, int bytesPerElement, int t)
{
assertMsg(bytesPerElement == sizeof(Vector3D<float>),
"grid element size doesn't match " << bytesPerElement << " vs " << sizeof(float));
gzread(gzf, ptr, sizeof(Vector3D<float>) * grid.getSizeX() * grid.getSizeY() * grid.getSizeZ());
float *ptrf = (float *)ptr;
for (IndexInt i = 0; i < grid.getSizeX() * grid.getSizeY() * grid.getSizeZ(); ++i) {
Vec3 v;
for (int c = 0; c < 3; ++c) {
v[c] = double(*ptrf);
ptrf++;
}
grid[grid.getSizeX() * grid.getSizeY() * grid.getSizeZ() * t + i] = v;
}
}
template<>
void gridReadConvert4d<Vec4>(
gzFile &gzf, Grid4d<Vec4> &grid, void *ptr, int bytesPerElement, int t)
{
assertMsg(bytesPerElement == sizeof(Vector4D<float>),
"grid element size doesn't match " << bytesPerElement << " vs " << sizeof(float));
gzread(gzf, ptr, sizeof(Vector4D<float>) * grid.getSizeX() * grid.getSizeY() * grid.getSizeZ());
float *ptrf = (float *)ptr;
for (IndexInt i = 0; i < grid.getSizeX() * grid.getSizeY() * grid.getSizeZ(); ++i) {
Vec4 v;
for (int c = 0; c < 4; ++c) {
v[c] = double(*ptrf);
ptrf++;
}
grid[grid.getSizeX() * grid.getSizeY() * grid.getSizeZ() * t + i] = v;
}
}
// make sure compatible grid types dont lead to errors...
static int unifyGridType(int type)
{
// real <> levelset
if (type & GridBase::TypeReal)
type |= GridBase::TypeLevelset;
if (type & GridBase::TypeLevelset)
type |= GridBase::TypeReal;
// vec3 <> mac
if (type & GridBase::TypeVec3)
type |= GridBase::TypeMAC;
if (type & GridBase::TypeMAC)
type |= GridBase::TypeVec3;
return type;
}
#endif // NO_ZLIB!=1
//*****************************************************************************
// grid data
//*****************************************************************************
template<class T> int writeGridTxt(const string &name, Grid<T> *grid)
{
debMsg("writing grid " << grid->getName() << " to text file " << name, 1);
ofstream ofs(name.c_str());
if (!ofs.good())
errMsg("writeGridTxt: can't open file " << name);
return 0;
FOR_IJK(*grid)
{
ofs << Vec3i(i, j, k) << " = " << (*grid)(i, j, k) << "\n";
}
ofs.close();
return 1;
}
int writeGridsTxt(const string &name, std::vector<PbClass *> *grids)
{
errMsg("writeGridsTxt: writing multiple grids to one .txt file not supported yet");
return 0;
}
int readGridsTxt(const string &name, std::vector<PbClass *> *grids)
{
errMsg("readGridsTxt: writing multiple grids from one .txt file not supported yet");
return 0;
}
template<class T> int writeGridRaw(const string &name, Grid<T> *grid)
{
debMsg("writing grid " << grid->getName() << " to raw file " << name, 1);
#if NO_ZLIB != 1
gzFile gzf = (gzFile)safeGzopen(name.c_str(), "wb1"); // do some compression
if (!gzf) {
errMsg("writeGridRaw: can't open file " << name);
return 0;
}
gzwrite(gzf, &((*grid)[0]), sizeof(T) * grid->getSizeX() * grid->getSizeY() * grid->getSizeZ());
return (gzclose(gzf) == Z_OK);
#else
debMsg("file format not supported without zlib", 1);
return 0;
#endif
}
template<class T> int readGridRaw(const string &name, Grid<T> *grid)
{
debMsg("reading grid " << grid->getName() << " from raw file " << name, 1);
#if NO_ZLIB != 1
gzFile gzf = (gzFile)safeGzopen(name.c_str(), "rb");
if (!gzf) {
errMsg("readGridRaw: can't open file " << name);
return 0;
}
IndexInt bytes = sizeof(T) * grid->getSizeX() * grid->getSizeY() * grid->getSizeZ();
IndexInt readBytes = gzread(gzf, &((*grid)[0]), bytes);
assertMsg(bytes == readBytes,
"can't read raw file, stream length does not match, " << bytes << " vs " << readBytes);
return (gzclose(gzf) == Z_OK);
#else
debMsg("file format not supported without zlib", 1);
return 0;
#endif
}
int writeGridsRaw(const string &name, std::vector<PbClass *> *grids)
{
errMsg("writeGridsRaw: writing multiple grids to one .raw file not supported yet");
return 0;
}
int readGridsRaw(const string &name, std::vector<PbClass *> *grids)
{
errMsg("readGridsRaw: reading multiple grids from one .raw file not supported yet");
return 0;
}
//! legacy headers for reading old files
typedef struct {
int dimX, dimY, dimZ;
int frames, elements, elementType, bytesPerElement, bytesPerFrame;
} UniLegacyHeader;
typedef struct {
int dimX, dimY, dimZ;
int gridType, elementType, bytesPerElement;
} UniLegacyHeader2;
typedef struct {
int dimX, dimY, dimZ;
int gridType, elementType, bytesPerElement;
char info[256];
unsigned long long timestamp;
} UniLegacyHeader3;
//! for auto-init & check of results of test runs , optionally returns info string of header
void getUniFileSize(const string &name, int &x, int &y, int &z, int *t, std::string *info)
{
x = y = z = 0;
#if NO_ZLIB != 1
gzFile gzf = (gzFile)safeGzopen(name.c_str(), "rb");
if (gzf) {
char ID[5] = {0, 0, 0, 0, 0};
gzread(gzf, ID, 4);
// v3
if ((!strcmp(ID, "MNT2")) || (!strcmp(ID, "M4T2"))) {
UniLegacyHeader3 head;
assertMsg(gzread(gzf, &head, sizeof(UniLegacyHeader3)) == sizeof(UniLegacyHeader3),
"can't read file, no header present");
x = head.dimX;
y = head.dimY;
z = head.dimZ;
// optionally , read fourth dim
if ((!strcmp(ID, "M4T2")) && t) {
int dimT = 0;
gzread(gzf, &dimT, sizeof(int));
(*t) = dimT;
}
}
// v4
if ((!strcmp(ID, "MNT3")) || (!strcmp(ID, "M4T3"))) {
UniHeader head;
assertMsg(gzread(gzf, &head, sizeof(UniHeader)) == sizeof(UniHeader),
"can't read file, no header present");
x = head.dimX;
y = head.dimY;
z = head.dimZ;
if (t)
(*t) = head.dimT;
}
gzclose(gzf);
}
#endif
if (info) {
std::ostringstream out;
out << x << "," << y << "," << z;
if (t && (*t) > 0)
out << "," << (*t);
*info = out.str();
}
}
Vec3 getUniFileSize(const string &name)
{
int x, y, z;
getUniFileSize(name, x, y, z);
return Vec3(Real(x), Real(y), Real(z));
}
static PyObject *_W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
{
try {
PbArgs _args(_linargs, _kwds);
FluidSolver *parent = _args.obtainParent();
bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
pbPreparePlugin(parent, "getUniFileSize", !noTiming);
PyObject *_retval = 0;
{
ArgLocker _lock;
const string &name = _args.get<string>("name", 0, &_lock);
_retval = toPy(getUniFileSize(name));
_args.check();
}
pbFinalizePlugin(parent, "getUniFileSize", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("getUniFileSize", e.what());
return 0;
}
}
static const Pb::Register _RP_getUniFileSize("", "getUniFileSize", _W_0);
extern "C" {
void PbRegister_getUniFileSize()
{
KEEP_UNUSED(_RP_getUniFileSize);
}
}
//! for test run debugging
void printUniFileInfoString(const string &name)
{
std::string info("<file not found>");
int x = -1, y = -1, z = -1, t = -1;
// use getUniFileSize to parse the different headers
getUniFileSize(name, x, y, z, &t, &info);
debMsg("File '" << name << "' info: " << info, 1);
}
static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
{
try {
PbArgs _args(_linargs, _kwds);
FluidSolver *parent = _args.obtainParent();
bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
pbPreparePlugin(parent, "printUniFileInfoString", !noTiming);
PyObject *_retval = 0;
{
ArgLocker _lock;
const string &name = _args.get<string>("name", 0, &_lock);
_retval = getPyNone();
printUniFileInfoString(name);
_args.check();
}
pbFinalizePlugin(parent, "printUniFileInfoString", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("printUniFileInfoString", e.what());
return 0;
}
}
static const Pb::Register _RP_printUniFileInfoString("", "printUniFileInfoString", _W_1);
extern "C" {
void PbRegister_printUniFileInfoString()
{
KEEP_UNUSED(_RP_printUniFileInfoString);
}
}
// actual read/write functions
template<class T> int writeGridUni(const string &name, Grid<T> *grid)
{
debMsg("Writing grid " << grid->getName() << " to uni file " << name, 1);
#if NO_ZLIB != 1
char ID[5] = "MNT3";
UniHeader head;
head.dimX = grid->getSizeX();
head.dimY = grid->getSizeY();
head.dimZ = grid->getSizeZ();
head.dimT = 0;
head.gridType = grid->getType();
head.bytesPerElement = sizeof(T);
snprintf(head.info, STR_LEN_GRID, "%s", buildInfoString().c_str());
MuTime stamp;
head.timestamp = stamp.time;
if (grid->getType() & GridBase::TypeInt)
head.elementType = 0;
else if (grid->getType() & GridBase::TypeReal)
head.elementType = 1;
else if (grid->getType() & GridBase::TypeVec3)
head.elementType = 2;
else {
errMsg("writeGridUni: unknown element type");
return 0;
}
gzFile gzf = (gzFile)safeGzopen(name.c_str(), "wb1"); // do some compression
if (!gzf) {
errMsg("writeGridUni: can't open file " << name);
return 0;
}
gzwrite(gzf, ID, 4);
# if FLOATINGPOINT_PRECISION != 1
// always write float values, even if compiled with double precision...
Grid<T> temp(grid->getParent());
// "misuse" temp grid as storage for floating point values (we have double, so it will always
// fit)
gridConvertWrite(gzf, *grid, &(temp[0]), head);
# else
void *ptr = &((*grid)[0]);
gzwrite(gzf, &head, sizeof(UniHeader));
gzwrite(gzf, ptr, sizeof(T) * head.dimX * head.dimY * head.dimZ);
# endif
return (gzclose(gzf) == Z_OK);
#else
debMsg("file format not supported without zlib", 1);
return 0;
#endif
};
template<class T> int readGridUni(const string &name, Grid<T> *grid)
{
debMsg("Reading grid " << grid->getName() << " from uni file " << name, 1);
#if NO_ZLIB != 1
gzFile gzf = (gzFile)safeGzopen(name.c_str(), "rb");
if (!gzf) {
errMsg("readGridUni: can't open file " << name);
return 0;
}
char ID[5] = {0, 0, 0, 0, 0};
gzread(gzf, ID, 4);
if (!strcmp(ID, "DDF2")) {
// legacy file format
UniLegacyHeader head;
assertMsg(gzread(gzf, &head, sizeof(UniLegacyHeader)) == sizeof(UniLegacyHeader),
"can't read file, no header present");
assertMsg(head.dimX == grid->getSizeX() && head.dimY == grid->getSizeY() &&
head.dimZ == grid->getSizeZ(),
"grid dim doesn't match");
assertMsg(head.bytesPerElement * head.elements == sizeof(T), "grid type doesn't match");
// skip flags
int numEl = head.dimX * head.dimY * head.dimZ;
gzseek(gzf, numEl, SEEK_CUR);
// actual grid read
gzread(gzf, &((*grid)[0]), sizeof(T) * numEl);
}
else if (!strcmp(ID, "MNT1")) {
// legacy file format 2
UniLegacyHeader2 head;
assertMsg(gzread(gzf, &head, sizeof(UniLegacyHeader2)) == sizeof(UniLegacyHeader2),
"can't read file, no header present");
assertMsg(head.dimX == grid->getSizeX() && head.dimY == grid->getSizeY() &&
head.dimZ == grid->getSizeZ(),
"grid dim doesn't match, " << Vec3(head.dimX, head.dimY, head.dimZ) << " vs "
<< grid->getSize());
assertMsg(head.gridType == grid->getType(),
"grid type doesn't match " << head.gridType << " vs " << grid->getType());
assertMsg(head.bytesPerElement == sizeof(T),
"grid element size doesn't match " << head.bytesPerElement << " vs " << sizeof(T));
gzread(gzf, &((*grid)[0]), sizeof(T) * head.dimX * head.dimY * head.dimZ);
}
else if (!strcmp(ID, "MNT2")) {
// a bit ugly, almost identical to MNT3
UniLegacyHeader3 head;
assertMsg(gzread(gzf, &head, sizeof(UniLegacyHeader3)) == sizeof(UniLegacyHeader3),
"can't read file, no header present");
assertMsg(head.dimX == grid->getSizeX() && head.dimY == grid->getSizeY() &&
head.dimZ == grid->getSizeZ(),
"grid dim doesn't match, " << Vec3(head.dimX, head.dimY, head.dimZ) << " vs "
<< grid->getSize());
assertMsg(unifyGridType(head.gridType) == unifyGridType(grid->getType()),
"grid type doesn't match " << head.gridType << " vs " << grid->getType());
# if FLOATINGPOINT_PRECISION != 1
Grid<T> temp(grid->getParent());
void *ptr = &(temp[0]);
gridReadConvert<T>(gzf, *grid, ptr, head.bytesPerElement);
# else
assertMsg(head.bytesPerElement == sizeof(T),
"grid element size doesn't match " << head.bytesPerElement << " vs " << sizeof(T));
gzread(gzf, &((*grid)[0]), sizeof(T) * head.dimX * head.dimY * head.dimZ);
# endif
}
else if (!strcmp(ID, "MNT3")) {
// current file format
UniHeader head;
assertMsg(gzread(gzf, &head, sizeof(UniHeader)) == sizeof(UniHeader),
"can't read file, no header present");
assertMsg(head.dimX == grid->getSizeX() && head.dimY == grid->getSizeY() &&
head.dimZ == grid->getSizeZ(),
"grid dim doesn't match, " << Vec3(head.dimX, head.dimY, head.dimZ) << " vs "
<< grid->getSize());
assertMsg(unifyGridType(head.gridType) == unifyGridType(grid->getType()),
"grid type doesn't match " << head.gridType << " vs " << grid->getType());
# if FLOATINGPOINT_PRECISION != 1
// convert float to double
Grid<T> temp(grid->getParent());
void *ptr = &(temp[0]);
gridReadConvert<T>(gzf, *grid, ptr, head.bytesPerElement);
# else
assertMsg(head.bytesPerElement == sizeof(T),
"grid element size doesn't match " << head.bytesPerElement << " vs " << sizeof(T));
gzread(gzf, &((*grid)[0]), sizeof(T) * head.dimX * head.dimY * head.dimZ);
# endif
}
else {
errMsg("readGridUni: Unknown header '" << ID << "' ");
return 0;
}
return (gzclose(gzf) == Z_OK);
#else
debMsg("file format not supported without zlib", 1);
return 0;
#endif
};
int writeGridsUni(const string &name, std::vector<PbClass *> *grids)
{
errMsg("writeGridsUni: writing multiple grids to one .uni file not supported yet");
return 0;
}
int readGridsUni(const string &name, std::vector<PbClass *> *grids)
{
errMsg("readGridsUni: reading multiple grids from one .uni file not supported yet");
return 0;
}
template<class T> int writeGridVol(const string &name, Grid<T> *grid)
{
debMsg("writing grid " << grid->getName() << " to vol file " << name, 1);
errMsg("writeGridVol: Type not yet supported!");
return 0;
}
int writeGridsVol(const string &name, std::vector<PbClass *> *grids)
{
errMsg("writeGridsVol: writing multiple grids to one .vol file not supported yet");
return 0;
}
int readGridsVol(const string &name, std::vector<PbClass *> *grids)
{
errMsg("readGridsVol: reading multiple grids from one .vol file not supported yet");
return 0;
}
struct volHeader {
char ID[3];
char version;
int encoding;
int dimX, dimY, dimZ;
int channels;
Vec3 bboxMin, bboxMax;
};
template<> int writeGridVol<Real>(const string &name, Grid<Real> *grid)
{
debMsg("writing real grid " << grid->getName() << " to vol file " << name, 1);
volHeader header;
header.ID[0] = 'V';
header.ID[1] = 'O';
header.ID[2] = 'L';
header.version = 3;
header.encoding = 1; // float32 precision
header.dimX = grid->getSizeX();
header.dimY = grid->getSizeY();
header.dimZ = grid->getSizeZ();
header.channels = 1; // only 1 channel
header.bboxMin = Vec3(-0.5);
header.bboxMax = Vec3(0.5);
FILE *fp = fopen(name.c_str(), "wb");
if (fp == NULL) {
errMsg("writeGridVol: Cannot open '" << name << "'");
return 0;
}
fwrite(&header, sizeof(volHeader), 1, fp);
#if FLOATINGPOINT_PRECISION == 1
// for float, write one big chunk
fwrite(&(*grid)[0], sizeof(float), grid->getSizeX() * grid->getSizeY() * grid->getSizeZ(), fp);
#else
// explicitly convert each entry to float - we might have double precision in mantaflow
FOR_IDX(*grid)
{
float value = (*grid)[idx];
fwrite(&value, sizeof(float), 1, fp);
}
#endif
return (!fclose(fp));
};
template<class T> int readGridVol(const string &name, Grid<T> *grid)
{
debMsg("writing grid " << grid->getName() << " to vol file " << name, 1);
errMsg("readGridVol: Type not yet supported!");
return 0;
}
template<> int readGridVol<Real>(const string &name, Grid<Real> *grid)
{
debMsg("reading real grid " << grid->getName() << " from vol file " << name, 1);
volHeader header;
FILE *fp = fopen(name.c_str(), "rb");
if (fp == NULL) {
errMsg("readGridVol: Cannot open '" << name << "'");
return 0;
}
// note, only very basic file format checks here!
assertMsg(fread(&header, 1, sizeof(volHeader), fp) == sizeof(volHeader),
"can't read file, no header present");
if (header.dimX != grid->getSizeX() || header.dimY != grid->getSizeY() ||
header.dimZ != grid->getSizeZ())
errMsg("grid dim doesn't match, " << Vec3(header.dimX, header.dimY, header.dimZ) << " vs "
<< grid->getSize());
#if FLOATINGPOINT_PRECISION != 1
errMsg("readGridVol: Double precision not yet supported");
return 0;
#else
const unsigned int s = sizeof(float) * header.dimX * header.dimY * header.dimZ;
assertMsg(fread(&((*grid)[0]), 1, s, fp) == s, "can't read file, no / not enough data");
#endif
return (!fclose(fp));
};
// 4d grids IO
template<class T> int writeGrid4dUni(const string &name, Grid4d<T> *grid)
{
debMsg("writing grid4d " << grid->getName() << " to uni file " << name, 1);
#if NO_ZLIB != 1
char ID[5] = "M4T3";
UniHeader head;
head.dimX = grid->getSizeX();
head.dimY = grid->getSizeY();
head.dimZ = grid->getSizeZ();
head.dimT = grid->getSizeT();
head.gridType = grid->getType();
head.bytesPerElement = sizeof(T);
snprintf(head.info, STR_LEN_GRID, "%s", buildInfoString().c_str());
MuTime stamp;
stamp.get();
head.timestamp = stamp.time;
if (grid->getType() & Grid4dBase::TypeInt)
head.elementType = 0;
else if (grid->getType() & Grid4dBase::TypeReal)
head.elementType = 1;
else if (grid->getType() & Grid4dBase::TypeVec3)
head.elementType = 2;
else if (grid->getType() & Grid4dBase::TypeVec4)
head.elementType = 2;
else {
errMsg("writeGrid4dUni: unknown element type");
return 0;
}
gzFile gzf = (gzFile)safeGzopen(name.c_str(), "wb1"); // do some compression
if (!gzf) {
errMsg("writeGrid4dUni: can't open file " << name);
return 0;
}
gzwrite(gzf, ID, 4);
# if FLOATINGPOINT_PRECISION != 1
Grid4d<T> temp(grid->getParent());
gridConvertWrite<Grid4d<T>>(gzf, *grid, &(temp[0]), head);
# else
gzwrite(gzf, &head, sizeof(UniHeader));
// can be too large - write in chunks
for (int t = 0; t < head.dimT; ++t) {
void *ptr = &((*grid)[head.dimX * head.dimY * head.dimZ * t]);
gzwrite(gzf, ptr, sizeof(T) * head.dimX * head.dimY * head.dimZ * 1);
}
# endif
return (gzclose(gzf) == Z_OK);
#else
debMsg("file format not supported without zlib", 1);
return 0;
#endif
};
//! note, reading 4d uni grids is slightly more complicated than 3d ones
//! as it optionally supports sliced reading
template<class T>
int readGrid4dUni(
const string &name, Grid4d<T> *grid, int readTslice, Grid4d<T> *slice, void **fileHandle)
{
if (grid)
debMsg("reading grid " << grid->getName() << " from uni file " << name, 1);
if (slice)
debMsg("reading slice " << slice->getName() << ",t=" << readTslice << " from uni file "
<< name,
1);
#if NO_ZLIB != 1
gzFile gzf = NULL;
char ID[5] = {0, 0, 0, 0, 0};
// optionally - reuse file handle, if valid one is passed in fileHandle pointer...
if ((!fileHandle) || (fileHandle && (*fileHandle == NULL))) {
gzf = (gzFile)safeGzopen(name.c_str(), "rb");
if (!gzf) {
errMsg("readGrid4dUni: can't open file " << name);
return 0;
}
gzread(gzf, ID, 4);
if (fileHandle) {
*fileHandle = gzf;
}
}
else {
// optimized read - reduced sanity checks
gzf = (gzFile)(*fileHandle);
void *ptr = &((*slice)[0]);
gzread(gzf, ptr, sizeof(T) * slice->getStrideT() * 1); // quick and dirty...
return 1;
}
if ((!strcmp(ID, "M4T2")) || (!strcmp(ID, "M4T3"))) {
int headerSize = -1;
// current file format
UniHeader head;
if (!strcmp(ID, "M4T3")) {
headerSize = sizeof(UniHeader);
assertMsg(gzread(gzf, &head, sizeof(UniHeader)) == sizeof(UniHeader),
"can't read file, no 4d header present");
if (FLOATINGPOINT_PRECISION == 1)
assertMsg(head.bytesPerElement == sizeof(T),
"4d grid element size doesn't match " << head.bytesPerElement << " vs "
<< sizeof(T));
}
// old header
if (!strcmp(ID, "M4T2")) {
UniLegacyHeader3 lhead;
headerSize = sizeof(UniLegacyHeader3) + sizeof(int);
assertMsg(gzread(gzf, &lhead, sizeof(UniLegacyHeader3)) == sizeof(UniLegacyHeader3),
"can't read file, no 4dl header present");
if (FLOATINGPOINT_PRECISION == 1)
assertMsg(lhead.bytesPerElement == sizeof(T),
"4d grid element size doesn't match " << lhead.bytesPerElement << " vs "
<< sizeof(T));
int fourthDim = 0;
gzread(gzf, &fourthDim, sizeof(fourthDim));
head.dimX = lhead.dimX;
head.dimY = lhead.dimY;
head.dimZ = lhead.dimZ;
head.dimT = fourthDim;
head.gridType = lhead.gridType;
}
if (readTslice < 0) {
assertMsg(head.dimX == grid->getSizeX() && head.dimY == grid->getSizeY() &&
head.dimZ == grid->getSizeZ(),
"grid dim doesn't match, " << Vec3(head.dimX, head.dimY, head.dimZ) << " vs "
<< grid->getSize());
assertMsg(unifyGridType(head.gridType) == unifyGridType(grid->getType()),
"grid type doesn't match " << head.gridType << " vs " << grid->getType());
// read full 4d grid
assertMsg(head.dimT == grid->getSizeT(),
"grid dim4 doesn't match, " << head.dimT << " vs " << grid->getSize());
// can be too large - read in chunks
# if FLOATINGPOINT_PRECISION != 1
Grid4d<T> temp(grid->getParent());
void *ptr = &(temp[0]);
for (int t = 0; t < head.dimT; ++t) {
gridReadConvert4d<T>(gzf, *grid, ptr, head.bytesPerElement, t);
}
# else
for (int t = 0; t < head.dimT; ++t) {
void *ptr = &((*grid)[head.dimX * head.dimY * head.dimZ * t]);
gzread(gzf, ptr, sizeof(T) * head.dimX * head.dimY * head.dimZ * 1);
}
# endif
}
else {
// read chosen slice only
assertMsg(head.dimX == slice->getSizeX() && head.dimY == slice->getSizeY() &&
head.dimZ == slice->getSizeZ(),
"grid dim doesn't match, " << Vec3(head.dimX, head.dimY, head.dimZ) << " vs "
<< slice->getSize());
assertMsg(unifyGridType(head.gridType) == unifyGridType(slice->getType()),
"grid type doesn't match " << head.gridType << " vs " << slice->getType());
# if FLOATINGPOINT_PRECISION != 1
errMsg("readGrid4dUni: NYI (2)"); // slice read not yet supported for double
return 0;
# else
assertMsg(slice, "No 3d slice grid data given");
assertMsg(readTslice < head.dimT,
"grid dim4 slice too large " << readTslice << " vs " << head.dimT);
void *ptr = &((*slice)[0]);
gzseek(gzf,
sizeof(T) * head.dimX * head.dimY * head.dimZ * readTslice + headerSize + 4,
SEEK_SET);
gzread(gzf, ptr, sizeof(T) * head.dimX * head.dimY * head.dimZ * 1);
# endif
}
}
else {
debMsg("Unknown header!", 1);
}
if (!fileHandle) {
return (gzclose(gzf) == Z_OK);
}
return 1;
#else
debMsg("file format not supported without zlib", 1);
return 0;
#endif
};
void readGrid4dUniCleanup(void **fileHandle)
{
#if NO_ZLIB != 1
gzFile gzf = NULL;
if (fileHandle) {
gzf = (gzFile)(*fileHandle);
gzclose(gzf);
*fileHandle = NULL;
}
#else
debMsg("file format not supported without zlib", 1);
#endif
}
template<class T> int writeGrid4dRaw(const string &name, Grid4d<T> *grid)
{
debMsg("writing grid4d " << grid->getName() << " to raw file " << name, 1);
#if NO_ZLIB != 1
gzFile gzf = (gzFile)safeGzopen(name.c_str(), "wb1"); // do some compression
if (!gzf) {
errMsg("writeGrid4dRaw: can't open file " << name);
return 0;
}
gzwrite(gzf,
&((*grid)[0]),
sizeof(T) * grid->getSizeX() * grid->getSizeY() * grid->getSizeZ() * grid->getSizeT());
return (gzclose(gzf) == Z_OK);
#else
debMsg("file format not supported without zlib", 1);
return 0;
#endif
}
template<class T> int readGrid4dRaw(const string &name, Grid4d<T> *grid)
{
debMsg("reading grid4d " << grid->getName() << " from raw file " << name, 1);
#if NO_ZLIB != 1
gzFile gzf = (gzFile)safeGzopen(name.c_str(), "rb");
if (!gzf) {
errMsg("readGrid4dRaw: can't open file " << name);
return 0;
}
IndexInt bytes = sizeof(T) * grid->getSizeX() * grid->getSizeY() * grid->getSizeZ() *
grid->getSizeT();
IndexInt readBytes = gzread(gzf, &((*grid)[0]), bytes);
assertMsg(bytes == readBytes,
"can't read raw file, stream length does not match, " << bytes << " vs " << readBytes);
return (gzclose(gzf) == Z_OK);
#else
debMsg("file format not supported without zlib", 1);
return 0;
#endif
}
//*****************************************************************************
// npz file support (warning - read works, but write generates uncompressed npz; i.e. not
// recommended for large volumes)
template<class T> int writeGridNumpy(const string &name, Grid<T> *grid)
{
#if FLOATINGPOINT_PRECISION != 1
errMsg("writeGridNumpy: Double precision not yet supported");
return 0;
#endif
#if NO_CNPY != 1
// find suffix to differentiate between npy <-> npz , TODO: check for actual "npy" string
std::string::size_type idx;
bool bUseNpz = false;
idx = name.rfind('.');
if (idx != std::string::npos) {
bUseNpz = name.substr(idx + 1) == "npz";
debMsg("Writing grid " << grid->getName() << " to npz file " << name, 1);
}
else {
debMsg("Writing grid " << grid->getName() << " to npy file " << name, 1);
}
// storage code
size_t uDim = 1;
if (grid->getType() & GridBase::TypeInt || grid->getType() & GridBase::TypeReal ||
grid->getType() & GridBase::TypeLevelset)
uDim = 1;
else if (grid->getType() & GridBase::TypeVec3 || grid->getType() & GridBase::TypeMAC)
uDim = 3;
else {
errMsg("writeGridNumpy: unknown element type");
return 0;
}
const std::vector<size_t> shape = {static_cast<size_t>(grid->getSizeZ()),
static_cast<size_t>(grid->getSizeY()),
static_cast<size_t>(grid->getSizeX()),
uDim};
if (bUseNpz) {
// note, the following generates a zip file without compression
if (grid->getType() & GridBase::TypeVec3 || grid->getType() & GridBase::TypeMAC) {
// cast to float* for export!
float *ptr = (float *)&((*grid)[0]);
cnpy::npz_save(name, "arr_0", ptr, shape, "w");
}
else {
T *ptr = &((*grid)[0]);
cnpy::npz_save(name, "arr_0", ptr, shape, "w");
}
}
else {
cnpy::npy_save(name, &grid[0], shape, "w");
}
return 1;
#else
debMsg("file format not supported without cnpy", 1);
return 0;
#endif
}
template<class T> int readGridNumpy(const string &name, Grid<T> *grid)
{
#if FLOATINGPOINT_PRECISION != 1
errMsg("readGridNumpy: Double precision not yet supported");
return 0;
#endif
#if NO_CNPY != 1
// find suffix to differentiate between npy <-> npz
std::string::size_type idx;
bool bUseNpz = false;
idx = name.rfind('.');
if (idx != std::string::npos) {
bUseNpz = name.substr(idx + 1) == "npz";
debMsg("Reading grid " << grid->getName() << " as npz file " << name, 1);
}
else {
debMsg("Reading grid " << grid->getName() << " as npy file " << name, 1);
}
cnpy::NpyArray gridArr;
if (bUseNpz) {
cnpy::npz_t fNpz = cnpy::npz_load(name);
gridArr = fNpz["arr_0"];
}
else {
gridArr = cnpy::npy_load(name);
}
// Check the file meta information
assertMsg(gridArr.shape[2] == grid->getSizeX() && gridArr.shape[1] == grid->getSizeY() &&
gridArr.shape[0] == grid->getSizeZ(),
"grid dim doesn't match, "
<< Vec3(gridArr.shape[2], gridArr.shape[1], gridArr.shape[0]) << " vs "
<< grid->getSize());
size_t uDim = 1;
if (grid->getType() & GridBase::TypeInt || grid->getType() & GridBase::TypeReal ||
grid->getType() & GridBase::TypeLevelset)
uDim = 1;
else if (grid->getType() & GridBase::TypeVec3 || grid->getType() & GridBase::TypeMAC)
uDim = 3;
else {
errMsg("readGridNumpy: unknown element type");
return 0;
}
assertMsg(gridArr.shape[3] == uDim,
"grid data dim doesn't match, " << gridArr.shape[3] << " vs " << uDim);
if (grid->getType() & GridBase::TypeVec3 || grid->getType() & GridBase::TypeMAC) {
// treated as float* for export , thus consider 3 elements
assertMsg(3 * gridArr.word_size == sizeof(T),
"vec3 grid data size doesn't match, " << 3 * gridArr.word_size << " vs "
<< sizeof(T));
}
else {
assertMsg(gridArr.word_size == sizeof(T),
"grid data size doesn't match, " << gridArr.word_size << " vs " << sizeof(T));
}
// copy back, TODO: beautify...
memcpy(&((*grid)[0]),
gridArr.data<T>(),
sizeof(T) * grid->getSizeX() * grid->getSizeY() * grid->getSizeZ());
return 1;
#else
debMsg("file format not supported without cnpy", 1);
return 0;
#endif
}
int writeGridsNumpy(const string &name, std::vector<PbClass *> *grids)
{
errMsg("writeGridsNumpy: writing multiple grids to one .npz file not supported yet");
return 0;
}
int readGridsNumpy(const string &name, std::vector<PbClass *> *grids)
{
errMsg("readGridsNumpy: reading multiple grids from one .npz file not supported yet");
return 0;
}
// adopted from getUniFileSize
void getNpzFileSize(
const string &name, int &x, int &y, int &z, int *t = NULL, std::string *info = NULL)
{
x = y = z = 0;
#if FLOATINGPOINT_PRECISION != 1
errMsg("getNpzFileSize: Double precision not yet supported");
#endif
#if NO_CNPY != 1
// find suffix to differentiate between npy <-> npz
cnpy::NpyArray gridArr;
cnpy::npz_t fNpz = cnpy::npz_load(name);
gridArr = fNpz["arr_0"];
z = gridArr.shape[0];
y = gridArr.shape[1];
x = gridArr.shape[2];
if (t)
(*t) = 0; // unused for now
#else
debMsg("file format not supported without cnpy", 1);
#endif
}
Vec3 getNpzFileSize(const string &name)
{
int x, y, z;
getNpzFileSize(name, x, y, z);
return Vec3(Real(x), Real(y), Real(z));
}
static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
{
try {
PbArgs _args(_linargs, _kwds);
FluidSolver *parent = _args.obtainParent();
bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
pbPreparePlugin(parent, "getNpzFileSize", !noTiming);
PyObject *_retval = 0;
{
ArgLocker _lock;
const string &name = _args.get<string>("name", 0, &_lock);
_retval = toPy(getNpzFileSize(name));
_args.check();
}
pbFinalizePlugin(parent, "getNpzFileSize", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("getNpzFileSize", e.what());
return 0;
}
}
static const Pb::Register _RP_getNpzFileSize("", "getNpzFileSize", _W_2);
extern "C" {
void PbRegister_getNpzFileSize()
{
KEEP_UNUSED(_RP_getNpzFileSize);
}
}
//*****************************************************************************
// helper functions
void quantizeReal(Real &v, const Real step)
{
int q = int(v / step + step * 0.5);
double qd = q * (double)step;
v = (Real)qd;
}
struct knQuantize : public KernelBase {
knQuantize(Grid<Real> &grid, Real step) : KernelBase(&grid, 0), grid(grid), step(step)
{
runMessage();
run();
}
inline void op(IndexInt idx, Grid<Real> &grid, Real step) const
{
quantizeReal(grid(idx), step);
}
inline Grid<Real> &getArg0()
{
return grid;
}
typedef Grid<Real> type0;
inline Real &getArg1()
{
return step;
}
typedef Real type1;
void runMessage()
{
debMsg("Executing kernel knQuantize ", 3);
debMsg("Kernel range"
<< " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
4);
};
void operator()(const tbb::blocked_range<IndexInt> &__r) const
{
for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
op(idx, grid, step);
}
void run()
{
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
}
Grid<Real> &grid;
Real step;
};
void quantizeGrid(Grid<Real> &grid, Real step)
{
knQuantize(grid, step);
}
static PyObject *_W_3(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
{
try {
PbArgs _args(_linargs, _kwds);
FluidSolver *parent = _args.obtainParent();
bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
pbPreparePlugin(parent, "quantizeGrid", !noTiming);
PyObject *_retval = 0;
{
ArgLocker _lock;
Grid<Real> &grid = *_args.getPtr<Grid<Real>>("grid", 0, &_lock);
Real step = _args.get<Real>("step", 1, &_lock);
_retval = getPyNone();
quantizeGrid(grid, step);
_args.check();
}
pbFinalizePlugin(parent, "quantizeGrid", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("quantizeGrid", e.what());
return 0;
}
}
static const Pb::Register _RP_quantizeGrid("", "quantizeGrid", _W_3);
extern "C" {
void PbRegister_quantizeGrid()
{
KEEP_UNUSED(_RP_quantizeGrid);
}
}
struct knQuantizeVec3 : public KernelBase {
knQuantizeVec3(Grid<Vec3> &grid, Real step) : KernelBase(&grid, 0), grid(grid), step(step)
{
runMessage();
run();
}
inline void op(IndexInt idx, Grid<Vec3> &grid, Real step) const
{
for (int c = 0; c < 3; ++c)
quantizeReal(grid(idx)[c], step);
}
inline Grid<Vec3> &getArg0()
{
return grid;
}
typedef Grid<Vec3> type0;
inline Real &getArg1()
{
return step;
}
typedef Real type1;
void runMessage()
{
debMsg("Executing kernel knQuantizeVec3 ", 3);
debMsg("Kernel range"
<< " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
4);
};
void operator()(const tbb::blocked_range<IndexInt> &__r) const
{
for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
op(idx, grid, step);
}
void run()
{
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
}
Grid<Vec3> &grid;
Real step;
};
void quantizeGridVec3(Grid<Vec3> &grid, Real step)
{
knQuantizeVec3(grid, step);
}
static PyObject *_W_4(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
{
try {
PbArgs _args(_linargs, _kwds);
FluidSolver *parent = _args.obtainParent();
bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
pbPreparePlugin(parent, "quantizeGridVec3", !noTiming);
PyObject *_retval = 0;
{
ArgLocker _lock;
Grid<Vec3> &grid = *_args.getPtr<Grid<Vec3>>("grid", 0, &_lock);
Real step = _args.get<Real>("step", 1, &_lock);
_retval = getPyNone();
quantizeGridVec3(grid, step);
_args.check();
}
pbFinalizePlugin(parent, "quantizeGridVec3", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("quantizeGridVec3", e.what());
return 0;
}
}
static const Pb::Register _RP_quantizeGridVec3("", "quantizeGridVec3", _W_4);
extern "C" {
void PbRegister_quantizeGridVec3()
{
KEEP_UNUSED(_RP_quantizeGridVec3);
}
}
// explicit instantiation
template int writeGridRaw<int>(const string &name, Grid<int> *grid);
template int writeGridRaw<Real>(const string &name, Grid<Real> *grid);
template int writeGridRaw<Vec3>(const string &name, Grid<Vec3> *grid);
template int writeGridUni<int>(const string &name, Grid<int> *grid);
template int writeGridUni<Real>(const string &name, Grid<Real> *grid);
template int writeGridUni<Vec3>(const string &name, Grid<Vec3> *grid);
template int writeGridVol<int>(const string &name, Grid<int> *grid);
template int writeGridVol<Vec3>(const string &name, Grid<Vec3> *grid);
template int writeGridTxt<int>(const string &name, Grid<int> *grid);
template int writeGridTxt<Real>(const string &name, Grid<Real> *grid);
template int writeGridTxt<Vec3>(const string &name, Grid<Vec3> *grid);
template int readGridRaw<int>(const string &name, Grid<int> *grid);
template int readGridRaw<Real>(const string &name, Grid<Real> *grid);
template int readGridRaw<Vec3>(const string &name, Grid<Vec3> *grid);
template int readGridUni<int>(const string &name, Grid<int> *grid);
template int readGridUni<Real>(const string &name, Grid<Real> *grid);
template int readGridUni<Vec3>(const string &name, Grid<Vec3> *grid);
template int readGridVol<int>(const string &name, Grid<int> *grid);
template int readGridVol<Vec3>(const string &name, Grid<Vec3> *grid);
template int readGrid4dUni<int>(
const string &name, Grid4d<int> *grid, int readTslice, Grid4d<int> *slice, void **fileHandle);
template int readGrid4dUni<Real>(const string &name,
Grid4d<Real> *grid,
int readTslice,
Grid4d<Real> *slice,
void **fileHandle);
template int readGrid4dUni<Vec3>(const string &name,
Grid4d<Vec3> *grid,
int readTslice,
Grid4d<Vec3> *slice,
void **fileHandle);
template int readGrid4dUni<Vec4>(const string &name,
Grid4d<Vec4> *grid,
int readTslice,
Grid4d<Vec4> *slice,
void **fileHandle);
template int writeGrid4dUni<int>(const string &name, Grid4d<int> *grid);
template int writeGrid4dUni<Real>(const string &name, Grid4d<Real> *grid);
template int writeGrid4dUni<Vec3>(const string &name, Grid4d<Vec3> *grid);
template int writeGrid4dUni<Vec4>(const string &name, Grid4d<Vec4> *grid);
template int readGrid4dRaw<int>(const string &name, Grid4d<int> *grid);
template int readGrid4dRaw<Real>(const string &name, Grid4d<Real> *grid);
template int readGrid4dRaw<Vec3>(const string &name, Grid4d<Vec3> *grid);
template int readGrid4dRaw<Vec4>(const string &name, Grid4d<Vec4> *grid);
template int writeGrid4dRaw<int>(const string &name, Grid4d<int> *grid);
template int writeGrid4dRaw<Real>(const string &name, Grid4d<Real> *grid);
template int writeGrid4dRaw<Vec3>(const string &name, Grid4d<Vec3> *grid);
template int writeGrid4dRaw<Vec4>(const string &name, Grid4d<Vec4> *grid);
template int writeGridNumpy<int>(const string &name, Grid<int> *grid);
template int writeGridNumpy<Real>(const string &name, Grid<Real> *grid);
template int writeGridNumpy<Vec3>(const string &name, Grid<Vec3> *grid);
template int readGridNumpy<int>(const string &name, Grid<int> *grid);
template int readGridNumpy<Real>(const string &name, Grid<Real> *grid);
template int readGridNumpy<Vec3>(const string &name, Grid<Vec3> *grid);
} // namespace Manta