htcp

Properties of water suspended in clouds
git clone git://git.meso-star.fr/htcp.git
Log | Files | Refs | README | LICENSE

commit c24e9dbe3b9619f8bddb3cc8276135c0ad89c227
parent a6b3f5ea231a4e70937cc0f11b362b0fa86fbda8
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Mon, 16 Jul 2018 16:16:45 +0200

Refactor les2htcp source code

Diffstat:
Msrc/les2htcp.c | 412++++++++++++++++++++++++++++++++++++++++++-------------------------------------
1 file changed, 220 insertions(+), 192 deletions(-)

diff --git a/src/les2htcp.c b/src/les2htcp.c @@ -13,8 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#define _POSIX_C_SOURCE 200809L /* mmap/getopt/close support */ -#define _DEFAULT_SOURCE 1 /* MAP_POPULATE support */ +#define _POSIX_C_SOURCE 200112L /* getopt/close support */ #include "les2htcp.h" @@ -29,7 +28,6 @@ #include <string.h> #include <unistd.h> /* getopt */ #include <fcntl.h> /* open */ -#include <sys/mman.h> /* mmap */ #include <sys/stat.h> /* S_IRUSR & S_IWUSR */ /******************************************************************************* @@ -186,6 +184,8 @@ grid_release(struct grid* grid) } \ } (void)0 +#define NDIMS_MAX 4 + static INLINE const char* ncerr_to_str(const int ncerr) { @@ -254,6 +254,63 @@ sizeof_nctype(const nc_type type) return sz; } +struct var { + size_t dim_len[NDIMS_MAX]; /* Length of the dimensions */ + int ndims; /* #dimensions */ + int id; /* NetCDF identifier */ + int type; /* Variable type */ +}; +static const struct var VAR_NULL = {0}; + +static INLINE res_T +ncvar_real_inq + (int nc, + const char* var_name, + const size_t expected_ndims, + struct var* var) +{ + int i; + int dimids[NDIMS_MAX]; /* NetCDF id of the data dimension */ + int err; + res_T res = RES_OK; + ASSERT(var_name && var && expected_ndims && expected_ndims <= NDIMS_MAX); + + /* Retrieve the NetCDF id of the variable */ + err = nc_inq_varid(nc, var_name, &var->id); + if(err != NC_NOERR) { + fprintf(stderr, "Could not inquire the '%s' variable -- %s\n", + var_name, ncerr_to_str(err)); + res = RES_BAD_ARG; + goto error; + } + + /* Inquire the dimensions of the variable */ + NC(inq_varndims(nc, var->id, &var->ndims)); + if((size_t)var->ndims != expected_ndims) { + fprintf(stderr, "The dimension of the '%s' variable must be %lu .\n", + var_name, (unsigned long)(expected_ndims)); + res = RES_BAD_ARG; + goto error; + } + NC(inq_vardimid(nc, var->id, dimids)); + FOR_EACH(i, 0, var->ndims) NC(inq_dimlen(nc, dimids[i], var->dim_len+i)); + + /* Inquire the type of the variable */ + NC(inq_vartype(nc, var->id, &var->type)); + if(var->type != NC_DOUBLE && var->type != NC_FLOAT) { + fprintf(stderr, + "The type of the '%s' variable cannot be %s. Expecting floating point data.\n", + var_name, nctype_to_str(var->type)); + res = RES_BAD_ARG; + goto error; + } + +exit: + return res; +error: + goto exit; +} + /******************************************************************************* * Helper functions ******************************************************************************/ @@ -366,58 +423,35 @@ setup_regular_dimension double* lower_pos, const int check) { - char* mem = NULL; - size_t len, start, i; + struct var var = VAR_NULL; + double* mem = NULL; + size_t start, i; double vxsz; - nc_type type; - int varid, dimid, ndims; - int err = NC_NOERR; res_T res = RES_OK; ASSERT(nc && var_name && voxel_size && lower_pos); - err = nc_inq_varid(nc, var_name, &varid); - if(err != NC_NOERR) { - fprintf(stderr, "Could not inquire the '%s' variable -- %s\n", - var_name, ncerr_to_str(err)); - res = RES_BAD_ARG; - goto error; - } - NC(inq_varndims(nc, varid, &ndims)); - if(ndims != 1) { - fprintf(stderr, "The dimension of the '%s' variable must be 1 .\n", var_name); - res = RES_BAD_ARG; - goto error; - } - - NC(inq_vardimid(nc, varid, &dimid)); - NC(inq_dimlen(nc, dimid, &len)); - ASSERT(len > 0); - - NC(inq_vartype(nc, varid, &type)); - if(type != NC_DOUBLE && type != NC_FLOAT) { - fprintf(stderr, "The type of the '%s' variable must be float or double.\n", - var_name); - res = RES_BAD_ARG; - goto error; - } + res = ncvar_real_inq(nc, var_name, 1, &var); + if(res != RES_OK) goto error; - #define AT(Mem, Id) (type == NC_FLOAT ? ((float*)Mem)[Id] : ((double*)Mem)[Id]) if(!check) { - char* raw = alloca(8); + const size_t len = 1; start = 0; - len = 1; - NC(get_vara(nc, varid, &start, &len, raw)); - vxsz = AT(raw, 0) * 2; /* Assume that the grid starts at 0 */ + NC(get_vara_double(nc, var.id, &start, &len, &vxsz)); + /* Assume that the coordinate is defined at the center of the cell and that + * the grid starts at 0 */ + vxsz *= 2; } else { - mem = mem_alloc(len*sizeof_nctype(type)); + mem = mem_alloc(var.dim_len[0]*sizeof(double)); if(!mem) { fprintf(stderr, "Could not allocate memory for the '%s' variable.\n", var_name); res = RES_MEM_ERR; goto error; } start = 0; - NC(get_vara(nc, varid, &start, &len, mem)); - vxsz = AT(mem, 0) * 2; /* Assume that the grid starts from 0 */ + NC(get_vara_double(nc, var.id, &start, &var.dim_len[0], mem)); + /* Assume that the coordinate is defined at the center of the cell and that + * the grid starts at 0 */ + vxsz = mem[0] * 2; } if(vxsz <= 0) { @@ -429,8 +463,8 @@ setup_regular_dimension if(check) { /* Check that the dimension is regular */ - FOR_EACH(i, 1, len) { - if(!eq_eps(AT(mem, i) - AT(mem, i-1), vxsz, 1.e-6)) { + FOR_EACH(i, 1, var.dim_len[0]) { + if(!eq_eps(mem[i] - mem[i-1], vxsz, 1.e-6)) { fprintf(stderr, "The voxel size of the '%s' variable must be regular.\n", var_name); res = RES_BAD_ARG; @@ -438,7 +472,6 @@ setup_regular_dimension } } } - #undef AT *voxel_size = vxsz; *lower_pos = 0; @@ -458,56 +491,26 @@ setup_Z_dimension int8_t* is_z_irregular, const int check) { - enum { Z, X, Y, NDIMS }; /* Helper constants */ - char* mem = NULL; /* Memory where NetCDF data are copied */ - char* mem2 = NULL; /* Temporary memory used to check the VLEV data */ + enum { Z, Y, X, NDIMS }; /* Helper constants */ + struct var var = VAR_NULL; + double* mem = NULL; /* Memory where NetCDF data are copied */ + double* mem2 = NULL; /* Temporary variable used to check NetCDF data */ size_t len[NDIMS]; size_t start[NDIMS]; - size_t dim_len[NDIMS]; size_t z; /* Id over the Z dimension */ - size_t i; /* Common id */ double vxsz; /* Voxel size */ double* pvxsz = NULL; /* Pointer toward voxel sizes */ - nc_type type; /* Type of the NetCDF VLEV variable */ - int varid; /* NetCDF id of the VLEV variable */ - int dimids[NDIMS]; /* NetCDF id of the VLEV dimensions */ int irregular; /* Boolean defining if the Z dimension is irregular */ - int ndims; /* #dims of the VLEV variable */ - int err = NC_NOERR; res_T res = RES_OK; ASSERT(nc && voxel_size && lower_pos && is_z_irregular); /* Retrieve the VLEV variable */ - err = nc_inq_varid(nc, "VLEV", &varid); - if(err != NC_NOERR) { - fprintf(stderr, "Could not inquire the 'VLEV' variable -- %s\n", - ncerr_to_str(err)); - res = RES_BAD_ARG; - goto error; - } - - /* Inquire the VLEV dimensionality */ - NC(inq_varndims(nc, varid, &ndims)); - if(ndims != NDIMS) { - fprintf(stderr, "The dimension of the 'VLEV' variable must be %i .\n", - NDIMS); - res = RES_BAD_ARG; - goto error; - } - NC(inq_vardimid(nc, varid, dimids)); - FOR_EACH(i, 0, NDIMS) NC(inq_dimlen(nc, dimids[i], len+i)); - - /* Inquire the type of the VLEV variable */ - NC(inq_vartype(nc, varid, &type)); - if(type != NC_DOUBLE && type != NC_FLOAT) { - fprintf(stderr, "The type of 'VLEV' variable must be float or double.\n"); - res = RES_BAD_ARG; - goto error; - } + res = ncvar_real_inq(nc, "VLEV", NDIMS, &var); + if(res != RES_OK) goto error; /* Allocate te memory space where a Z column of the VLEV variable is going to * be copied */ - mem = mem_alloc(len[Z]*sizeof_nctype(type)); + mem = mem_alloc(var.dim_len[Z]*sizeof(double)); if(!mem) { fprintf(stderr, "Could not allocate memory for the 'VLEV' variable.\n"); res = RES_MEM_ERR; @@ -515,15 +518,14 @@ setup_Z_dimension } /* Get only one Z column */ - start[X] = 0; dim_len[X] = 1; - start[Y] = 0; dim_len[Y] = 1; - start[Z] = 0; dim_len[Z] = len[Z]; - NC(get_vara(nc, varid, start, dim_len, mem)); - - #define AT(Mem, Id) (type == NC_FLOAT ? ((float*)Mem)[Id] : ((double*)Mem)[Id]) - - /* Assume that the Z dimension starts from 0 */ - vxsz = AT(mem, 0) * 2.0; + start[X] = 0; len[X] = 1; + start[Y] = 0; len[Y] = 1; + start[Z] = 0; len[Z] = var.dim_len[Z]; + NC(get_vara_double(nc, var.id, start, len, mem)); + + /* Assume that the coordinate is defined at the center of the cell and that + * the grid starts at 0 */ + vxsz = mem[0] * 2.0; if(vxsz <= 0) { fprintf(stderr, "The 'VLEV' variable can't have negative or null values.\n"); res = RES_BAD_ARG; @@ -531,13 +533,13 @@ setup_Z_dimension } /* Check if the Z dimension is regular */ - FOR_EACH(z, 1, len[Z]) { - if(!eq_eps(AT(mem, z) - AT(mem, z-1), vxsz, 1.e-6)) break; + FOR_EACH(z, 1, var.dim_len[Z]) { + if(!eq_eps(mem[z] - mem[z-1], vxsz, 1.e-6)) break; } - irregular = (z != len[Z]); + irregular = (z != var.dim_len[Z]); /* Setup the size of the voxel */ - pvxsz = mem_alloc(sizeof(double) * (irregular ? len[Z] : 1)); + pvxsz = mem_alloc(sizeof(double) * (irregular ? var.dim_len[Z] : 1)); if(!pvxsz) { fprintf(stderr, "Could not allocate memory for the voxel size along the Z dimension.\n"); @@ -547,8 +549,8 @@ setup_Z_dimension pvxsz[0] = vxsz; if(irregular) { - FOR_EACH(z, 1, len[Z]) { - pvxsz[z] = (AT(mem, z) - (AT(mem, z-1) + pvxsz[z-1]*0.5)) * 2.0; + FOR_EACH(z, 1, var.dim_len[Z]) { + pvxsz[z] = (mem[z] - (mem[z-1] + pvxsz[z-1]*0.5)) * 2.0; if(pvxsz[z] <= 0) { fprintf(stderr, "The 'VLEV' variable can't have negative or null values.\n"); @@ -562,7 +564,7 @@ setup_Z_dimension if(check) { size_t ix, iy; - mem2 = mem_alloc(len[Z]*sizeof_nctype(type)); + mem2 = mem_alloc(var.dim_len[Z]*sizeof(double)); if(!mem2) { fprintf(stderr, "Could not allocate memory to check the 'VLEV' variable.\n"); @@ -570,13 +572,13 @@ setup_Z_dimension goto error; } - FOR_EACH(iy, 0, len[Y]) { + FOR_EACH(iy, 0, var.dim_len[Y]) { start[Y] = iy; - FOR_EACH(ix, 1, len[X]) { + FOR_EACH(ix, 1, var.dim_len[X]) { start[X] = ix; - NC(get_vara(nc, varid, start, dim_len, mem2)); - FOR_EACH(z, 0, len[Z]) { - if(!eq_eps(AT(mem2, z), AT(mem, z), 1.e-6)) { + NC(get_vara_double(nc, var.id, start, len, mem2)); + FOR_EACH(z, 0, var.dim_len[Z]) { + if(!eq_eps(mem2[z], mem[z], 1.e-6)) { fprintf(stderr, "The Z columns of the 'VLEV' variable must be the same.\n"); res = RES_BAD_ARG; @@ -586,7 +588,6 @@ setup_Z_dimension } } } - #undef AT *lower_pos = 0; *voxel_size = pvxsz; @@ -600,61 +601,44 @@ error: goto exit; } +/* Functor used to convert NetCDF data */ +typedef void (*convert_data_T) + (double* data, /* Input data */ + const size_t start[4], /* Start Index of the data in the NetCDF */ + const size_t len[4], /* Lenght of the loaded data */ + void* context); /* User defined data */ + +/* Write data of the variable "var_name" into "stream". The data are loaded + * slice by slice, where each slice is a 2D array whose dimensions are + * "W_E_direction X S_N_direction". The "convert" functor is invoked on each + * loaded slice. */ static res_T -write_data(int nc, const char* var_name, FILE* stream) +write_data + (int nc, + const char* var_name, + FILE* stream, + convert_data_T convert_func, /* May be NULL <=> No conversion */ + void* convert_ctx) /* Sent as the last argument of "convert_func" */ { - enum { TIME, Z, X, Y, NDIMS }; /* Helper constants */ + enum { TIME, Z, Y, X, NDIMS }; /* Helper constants */ + struct var var = VAR_NULL; double* mem = NULL; /* Memory where NetCDF data are copied */ size_t start[NDIMS]; - size_t dim_len[NDIMS]; size_t len[NDIMS]; size_t slice_len; /* #elements per slice the 3D grid */ - size_t i; /* Common id */ size_t t; /* Id over the time dimension */ size_t z; /* Id over the Z dimension */ - nc_type type; - int varid; /* NetCDF id of the data to write */ - int ndims; /* #dimensions of the NetCDF data to write */ - int dimids[NDIMS]; /* NetCDF id of the data dimension */ - int err = NC_NOERR; res_T res = RES_OK; CHK(var_name); - /* Retrieve the NetCDF id of the variable */ - err = nc_inq_varid(nc, var_name, &varid); - if(err != NC_NOERR) { - fprintf(stderr, "Could not inquire the '%s' variable -- %s\n", - var_name, ncerr_to_str(err)); - res = RES_BAD_ARG; - goto error; - } - - /* Inquire the dimensions of the variable */ - NC(inq_varndims(nc, varid, &ndims)); - if(ndims != NDIMS) { - fprintf(stderr, "The dimension of the '%s' variable must be %i .\n", - var_name, NDIMS); - res = RES_BAD_ARG; - goto error; - } - NC(inq_vardimid(nc, varid, dimids)); - FOR_EACH(i, 0, NDIMS) NC(inq_dimlen(nc, dimids[i], len+i)); - - /* Inquire the type of the variable */ - NC(inq_vartype(nc, varid, &type)); - if(type != NC_DOUBLE && type != NC_FLOAT) { - fprintf(stderr, - "The type of the '%s' variable cannot be %s. Expecting floating point data.\n", - var_name, nctype_to_str(type)); - res = RES_BAD_ARG; - goto error; - } + res = ncvar_real_inq(nc, var_name, NDIMS, &var); + if(res != RES_OK) goto error; /* Alloc the memory space where the variable data will be copied. Note that, * in order to reduce memory consumption, only one slice is read at a given * time and Z position. */ - slice_len = len[X]*len[Y]; /* # elements per slice */ + slice_len = var.dim_len[X]*var.dim_len[Y]; /* # elements per slice */ mem = mem_alloc(slice_len*sizeof(double)); if(!mem) { @@ -665,19 +649,21 @@ write_data(int nc, const char* var_name, FILE* stream) } /* Read the whole slice */ - start[X] = 0; dim_len[X] = len[X]; - start[Y] = 0; dim_len[Y] = len[Y]; + start[X] = 0; len[X] = var.dim_len[X]; + start[Y] = 0; len[Y] = var.dim_len[Y]; - FOR_EACH(t, 0, len[TIME]) { - start[TIME] = t, dim_len[TIME] = 1; - FOR_EACH(z, 0, len[Z]) { + FOR_EACH(t, 0, var.dim_len[TIME]) { + start[TIME] = t, len[TIME] = 1; + FOR_EACH(z, 0, var.dim_len[Z]) { size_t n; - start[Z] = z; dim_len[Z] = 1; + start[Z] = z; len[Z] = 1; - NC(get_vara_double(nc, varid, start, dim_len, mem)); /* Fetch the slice data */ + NC(get_vara_double(nc, var.id, start, len, mem)); /* Fetch the slice data */ + + if(convert_func) convert_func(mem, start, len, convert_ctx); /* Write data */ - n = fwrite(mem, sizeof_nctype(NC_DOUBLE), slice_len, stream); + n = fwrite(mem, sizeof(double), slice_len, stream); if(n != slice_len) { fprintf(stderr, "Error writing data of the '%s' variable -- '%s'.\n", var_name, strerror(errno)); @@ -694,19 +680,82 @@ error: goto exit; } +struct THT_to_T_context { + double* mem; /* Memory where to store a PABST slice */ + size_t len; /* lenght of the mem */ + int pabst_id; /* NetCDF id of the PABST variable */ + int nc; /* NetCDF handler */ +}; +static const struct THT_to_T_context THT_TO_T_CONTEXT_NULL = { NULL, 0, 0, 0 }; + +static void +THT_to_T_context_release(struct THT_to_T_context* ctx) +{ + ASSERT(ctx); + if(ctx->mem) mem_rm(ctx->mem); +} + +static res_T +THT_to_T_context_init(struct THT_to_T_context* ctx, int nc) +{ + enum { TIME, Z, Y, X, NDIMS }; /* Helper constants */ + struct var var = VAR_NULL; + res_T res = RES_OK; + ASSERT(ctx); + + *ctx = THT_TO_T_CONTEXT_NULL; + + res = ncvar_real_inq(nc, "PABST", NDIMS, &var); + if(res != RES_OK) goto error; + + /* Allocate memory to store one slice of PABST data */ + ctx->len = var.dim_len[X] * var.dim_len[Y]; + ctx->mem = mem_alloc(ctx->len*sizeof(double)); + if(!ctx->mem) { + fprintf(stderr, + "Could not allocate the temporary memory space of the THT_to_T_context " + "data structure.\n"); + res = RES_MEM_ERR; + goto error; + } + + ctx->pabst_id = var.id; + ctx->nc = nc; + +exit: + return res; +error: + THT_to_T_context_release(ctx); + goto exit; +} + /* Convert potential temperature to temperature * T(i)=THT(i)*(PABST(i)/P0)^(R/(M_DA*Cp0)) */ static void -THT_to_T(const size_t n, const double* PABST, double* THT) +THT_to_T + (double* THT, + const size_t start[4], /* Start id of the THT var in the NetCDF file */ + const size_t len[4], /* Len of the loaded THT */ + void* context) { + struct THT_to_T_context* ctx = context; const double P0 = 101325; /* In Pa */ const double R = 8.3144598; /* In kg.m^2.s^-2.mol^-1.K */ const double M_DA = 28.9644e-3; /* In kg.mol^-1 */ const double Cp0 = 1.005e+3; /* In J/kg/K */ const double exponent = R/(M_DA * Cp0); double* T = THT; - size_t i; - ASSERT(n && PABST && THT); + double* PABST; + size_t i, n; + ASSERT(THT && start && len && context); + + n = len[0] * len[1] * len[2] * len[3]; + CHK(n <= ctx->len); + PABST = ctx->mem; + + /* Fetch the slice pressure data */ + NC(get_vara_double(ctx->nc, ctx->pabst_id, start, len, PABST)); + FOR_EACH(i, 0, n) T[i] = THT[i] * pow(PABST[i]/P0, exponent); } @@ -719,6 +768,8 @@ main(int argc, char** argv) FILE* stream = stdout; struct grid grid = GRID_NULL; struct args args = ARGS_DEFAULT; + struct THT_to_T_context THT_to_T_ctx = THT_TO_T_CONTEXT_NULL; + int err = 0; int err_nc = NC_NOERR; int nc = INVALID_ID; @@ -741,6 +792,7 @@ main(int argc, char** argv) } #define CALL(Func) { if(RES_OK != (res = Func)) goto error; } (void)0 + CALL(setup_definition(nc, &grid.nx, &grid.ny, &grid.nz, &grid.ntimes)); CALL(setup_regular_dimension (nc, "W_E_direction", &grid.vxsz_x, grid.lower+0, args.check)); @@ -748,7 +800,6 @@ main(int argc, char** argv) (nc, "S_N_direction", &grid.vxsz_y, grid.lower+1, args.check)); CALL(setup_Z_dimension (nc, &grid.vxsz_z, grid.lower+2, &grid.is_z_irregular, args.check)); - #undef CALL #define WRITE(Var, N, Name) { \ if(fwrite((Var), sizeof(*(Var)), (N), stream) != (N)) { \ @@ -759,11 +810,6 @@ main(int argc, char** argv) } (void)0 if(!args.no_output) { const int64_t pagesz = (int64_t)args.pagesize; - double* PABST = NULL; - double* THT = NULL; - long PABST_off, THT_off; - size_t PABST_len, THT_len; - size_t n; WRITE(&pagesz, 1, "page size"); WRITE(&grid.is_z_irregular, 1, "'irregular' Z boolean"); @@ -777,48 +823,30 @@ main(int argc, char** argv) WRITE(grid.vxsz_z, grid.is_z_irregular?(size_t)grid.nz:1, "Z voxel size(s)"); fseek(stream, ALIGN_SIZE(ftell(stream),(off_t)pagesz), SEEK_SET);/*padding*/ - write_data(nc, "RVT", stream); + CALL(write_data(nc, "RVT", stream, NULL, NULL)); fseek(stream, ALIGN_SIZE(ftell(stream),(off_t)pagesz), SEEK_SET);/*padding*/ - - write_data(nc, "RCT", stream); + CALL(write_data(nc, "RCT", stream, NULL, NULL)); fseek(stream, ALIGN_SIZE(ftell(stream),(off_t)pagesz), SEEK_SET);/*padding*/ - - PABST_off = ftell(stream); - write_data(nc, "PABST", stream); + CALL(write_data(nc, "PABST", stream, NULL, NULL)); fseek(stream, ALIGN_SIZE(ftell(stream),(off_t)pagesz), SEEK_SET);/*padding*/ - PABST_len = (size_t)(ftell(stream) - PABST_off); - THT_off = ftell(stream); - write_data(nc, "THT", stream); - fseek(stream, ALIGN_SIZE(ftell(stream),(off_t)pagesz), SEEK_SET);/*padding*/ - THT_len = (size_t)(ftell(stream) - THT_off); - - CHK(fclose(stream) == 0); - CHK(stream = fopen(args.output, "rw")); - - #define MMAP(Var, Prot) { \ - Var = mmap(NULL, Var##_len, Prot, MAP_PRIVATE|MAP_POPULATE, \ - fileno(stream), Var##_off); \ - if(Var == MAP_FAILED) { \ - fprintf(stderr, "%s: could not map the "STR(Var)" data -- %s.\n", \ - args.input, strerror(errno)); \ - goto error; \ - } \ - } (void)0 - MMAP(PABST, PROT_READ); - MMAP(THT, PROT_READ|PROT_WRITE); - #undef MMAP - - n = (size_t)(grid.nx * grid.ny * grid.nz * grid.ntimes); - THT_to_T(n, PABST, THT); - - CHK(munmap(PABST, PABST_len) == 0); - CHK(munmap(THT, THT_len) == 0); + CALL(THT_to_T_context_init(&THT_to_T_ctx, nc)); + CALL(write_data(nc, "THT", stream, THT_to_T, &THT_to_T_ctx)); + if(!IS_ALIGNED(ftell(stream), (size_t)pagesz)) { + /* Padding to ensure that the size is aligned on the page size. Note that + * one char is written to positioned the EOF indicator */ + const char byte = 0; + fseek(stream, ALIGN_SIZE(ftell(stream),(off_t)pagesz)-1, SEEK_SET); + WRITE(&byte, 1, "Dummy Byte"); + } } #undef WRITE + #undef CALL exit: grid_release(&grid); + THT_to_T_context_release(&THT_to_T_ctx); + if(stream != stdout) CHK(fclose(stream) == 0); if(nc != INVALID_ID) NC(close(nc)); if(mem_allocated_size() != 0) { fprintf(stderr, "Memory leaks: %lu Bytes\n",