/*@@ @file Write.c @date Thu 18 April 2002 @author Thomas Radke @desc Output two-dimensional slices in Jpeg image format. @enddesc @version $Id$ @@*/ #include #include #include "cctk.h" #include "cctk_Parameters.h" #include "util_Table.h" #include "CactusBase/IOUtil/src/ioutil_AdvertisedFiles.h" #include "ioJpegGH.h" /* the rcs ID and its dummy function to use it */ static const char *rcsid = "$Header$"; CCTK_FILEVERSION(CactusIO_IOJpeg_Write_c) /******************************************************************** ******************** Internal Routines ************************ ********************************************************************/ static void WriteData (const cGH *GH, int vindex, const char *alias, int dim, int dir, CCTK_REAL min, CCTK_REAL max, const CCTK_INT hsize[2], const void *hdata); static void *RefineData (CCTK_INT input_dims[2], const void *input_data); /*@@ @routine IOJpeg_Write @date Thu 18 April 2002 @author Thomas Radke @desc Writes the slices of a variable into separate Jpeg files. @enddesc @calls Hyperslab_GlobalMappingByIndex Hyperslab_FreeMapping Hyperslab_GetList OpenFile WriteData @var GH @vdesc pointer to CCTK GH @vtype const cGH * @vio in @endvar @var vindex @vdesc index of variable to output @vtype CCTK_INT @vio in @endvar @var alias @vdesc alias name of variable to output @vtype const char * @vio in @endvar @returntype int @returndesc 0 for success, or
-1 if variable has no storage assigned
-2 if output file couldn't be opened
-3 if hyperslab for coordinates and/or variable couldn't be extracted @endreturndesc @@*/ int IOJpeg_Write (const cGH *GH, CCTK_INT vindex, const char *alias) { const ioJpegGH *myGH; int i, mapping, total_hsize; int dir, dir_i, dir_j, maxdir, myproc, groupindex; cGroup gdata; char *fullname; CCTK_INT origin[3], direction[6], hsize[2]; const CCTK_INT extent[2] = {-1, -1}; void *hdata, *outdata; CCTK_REAL min, max; const CCTK_INT htype = CCTK_VARIABLE_REAL; DECLARE_CCTK_PARAMETERS /* get the variable name and group information */ fullname = CCTK_FullName (vindex); groupindex = CCTK_GroupIndexFromVarI (vindex); CCTK_GroupData (groupindex, &gdata); /* check if variable has storage assigned */ if (! CCTK_QueryGroupStorageI (GH, groupindex)) { CCTK_VWarn (2, __LINE__, __FILE__, CCTK_THORNSTRING, "No IOJpeg output for '%s' (no storage)", fullname); free (fullname); return (-1); } /* get the handle for IOJpeg extensions */ myproc = CCTK_MyProc (GH); myGH = (const ioJpegGH *) CCTK_GHExtension (GH, "IOJpeg"); /* set the minimum/maximum for the colormap */ if (CCTK_Equals (colormap, "custom")) { min = colormap_min; max = colormap_max; } else { i = CCTK_ReductionHandle ("minimum"); CCTK_Reduce (GH, 0, i, 1, CCTK_VARIABLE_REAL, &min, 1, vindex); i = CCTK_ReductionHandle ("maximum"); CCTK_Reduce (GH, 0, i, 1, CCTK_VARIABLE_REAL, &max, 1, vindex); } /* get the number of slices to output */ /* in general: maxdir = gdata.dim * (gdata.dim - 1) / 2; */ maxdir = gdata.dim == 2 ? 1 : 3; /* now do the actual I/O looping over all directions */ for (dir = 0; dir < maxdir; dir++) { /* get the directions to span the hyperslab */ if (dir == 0) { dir_i = 0; dir_j = 1; /* xy */ } else if (dir == 1) { dir_i = 0; dir_j = 2; /* xz */ } else { dir_i = 1; dir_j = 2; /* yz */ } /* set the origin using the slice center from IOUtil */ memset (origin, 0, sizeof (origin)); if (gdata.grouptype == CCTK_GF) { origin[maxdir-dir-1] = myGH->sp2xyz[gdata.dim - 1][dir]; } /* set the direction vector */ memset (direction, 0, sizeof (direction)); direction[dir_i] = direction[gdata.dim + dir_j] = 1; mapping = Hyperslab_GlobalMappingByIndex (GH, vindex, 2, direction, origin, extent, NULL, -1, NULL, hsize); if (mapping < 0) { CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING, "Failed to define hyperslab mapping for variable '%s'", fullname); continue; } total_hsize = hsize[0] * hsize[1] * CCTK_VarTypeSize (gdata.vartype); if (total_hsize <= 0) { CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING, "Selected hyperslab has zero size for variable '%s' " "direction %d", fullname, dir); Hyperslab_FreeMapping (mapping); continue; } /* allocate hyperslab buffer */ hdata = myproc == 0 ? malloc (total_hsize) : NULL; /* get the hyperslab */ i = Hyperslab_Get (GH, mapping, 0, vindex, 0, htype, hdata); if (i) { CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING, "Failed to extract hyperslab for variable '%s'", fullname); } /* release the mapping structure */ Hyperslab_FreeMapping (mapping); /* and dump the data to file */ if (myproc == 0) { if (i == 0) { /* refine the 2D slice if requested */ outdata = refinement_factor > 1 ? RefineData (hsize, hdata) : hdata; if (! outdata) { CCTK_WARN (1, "Failed to refine 2D array"); outdata = hdata; } WriteData (GH, vindex, alias, gdata.dim, dir, min, max, hsize, outdata); if (outdata != hdata) { free (outdata); } } /* clean up */ free (hdata); } } /* end of looping through xyz directions */ free (fullname); return (0); } /******************************************************************** ******************** Internal Routines ************************ ********************************************************************/ /*@@ @routine RefineData @date Thu 4 November 2004 @author Thomas Radke @desc Refines a given 2D input array by a certain factor @enddesc @returntype void * @returndesc a pointer to the allocated refined output array (must be freed by the caller), or NULL in case of an error @endreturndesc @@*/ static void *RefineData (CCTK_INT input_dims[2], const void *input_data) { const CCTK_REAL coord_origin[2] = {0.0, 0.0}; CCTK_REAL coord_delta[2]; const CCTK_INT array_type_codes[2] = {CCTK_VARIABLE_REAL, CCTK_VARIABLE_REAL}; CCTK_REAL *interp_coords[2], *refined_data; int i, j, interp_handle, table_handle, N_interp_points; CCTK_INT output_dims[2]; DECLARE_CCTK_PARAMETERS interp_handle = CCTK_InterpHandle ("uniform cartesian"); if (interp_handle < 0) { CCTK_WARN (1, "Couldn't get handle for interpolation operator 'uniform " "cartesian'. Did you forget to activate a thorn providing " "CCTK_InterpLocalUniform() ?"); return (NULL); } table_handle = Util_TableCreateFromString ("order = 1"); coord_delta[0] = coord_delta[1] = refinement_factor; /* leave one grid point at the boundary as interpolation stencil */ output_dims[0] = refinement_factor * (input_dims[0] - 1) - 2; output_dims[1] = refinement_factor * (input_dims[1] - 1) - 2; N_interp_points = output_dims[0] * output_dims[1]; interp_coords[0] = malloc (2 * N_interp_points * sizeof (CCTK_REAL)); interp_coords[1] = interp_coords[0] + N_interp_points; for (j = 0; j < output_dims[1]; j++) { for (i = 0; i < output_dims[0]; i++) { *interp_coords[0]++ = i + 1; *interp_coords[1]++ = j + 1; } } interp_coords[0] -= N_interp_points; interp_coords[1] -= N_interp_points; refined_data = malloc (N_interp_points * sizeof (CCTK_REAL)); if (CCTK_InterpLocalUniform (2, interp_handle, table_handle, coord_origin, coord_delta, N_interp_points, CCTK_VARIABLE_REAL, (const void *const *) interp_coords, 1, input_dims, array_type_codes, &input_data, 1, array_type_codes, (void *const *) &refined_data) != 0) { CCTK_WARN (1, "Failed to interpolate 2D array"); free (refined_data); refined_data = NULL; } else { input_dims[0] = output_dims[0]; input_dims[1] = output_dims[1]; } free (interp_coords[0]); Util_TableDestroy (table_handle); return (refined_data); } /*@@ @routine WriteData @date Thu 18 April 2002 @author Thomas Radke @desc Writes the given hyperslab into a Jpeg output file. @enddesc @@*/ static void WriteData (const cGH *GH, int vindex, const char *alias, int dim, int dir, CCTK_REAL min, CCTK_REAL max, const CCTK_INT hsize[2], const void *hdata) { FILE *file; unsigned char *dataout; const ioJpegGH *myGH; ioAdvertisedFileDesc advertised_file; char *filename, *fullname; char slicename[30]; const char *extensions[] = {"xy", "xz", "yz"}; DECLARE_CCTK_PARAMETERS myGH = (const ioJpegGH *) CCTK_GHExtension (GH, "IOJpeg"); /* allocate the RGB image buffer */ dataout = (unsigned char *) malloc (3 * hsize[0] * hsize[1]); AutoColorDataSlice (hsize[0], hsize[1], hdata, dataout, min, max, colormap_bias, colormap_factor); /* open the file */ if (dim == 2) { strcpy (slicename, "2D"); } else { /* give the slice origin as range [1 .. n] */ sprintf (slicename, "%s_[%d]", extensions[dir], myGH->sp2xyz[dim-1][dir]); } filename = (char *) malloc (strlen (myGH->out_dir) + strlen (alias) + sizeof (slicename) + 20); if (CCTK_Equals (mode, "remove")) { sprintf (filename, "%s%s_%s.jpeg", myGH->out_dir, alias, slicename); } else { sprintf (filename, "%s%s_%s.it_%d.jpeg", myGH->out_dir, alias, slicename, GH->cctk_iteration); } file = fopen (filename, "w"); if (file) { /* write the data */ WriteJPEGToFileRGB (hsize[0], hsize[1], dataout, colormap_quality, file); /* advertise the file for downloading */ if (CCTK_Equals (mode, "remove") && myGH->out_last[vindex] < 0) { fullname = CCTK_FullName (vindex); advertised_file.slice = slicename; advertised_file.thorn = CCTK_THORNSTRING; advertised_file.varname = fullname; advertised_file.description = "Jpegs of slices"; advertised_file.mimetype = "image/jpeg"; IOUtil_AdvertiseFile (GH, filename, &advertised_file); free (fullname); } /* close the file */ fclose (file); } else { CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING, "Cannot open IOJpeg output file '%s'", filename); } /* clean up */ free (dataout); free (filename); }