/*@@ @file Write.c @date Fri May 21 1999 @author Thomas Radke, Gerd Lanfermann @desc File handling routines for IOHDF5. @enddesc @version $Id$ @@*/ #include #include "cctk.h" #include "cctk_Parameters.h" #include "StoreNamedData.h" #include "CactusBase/IOUtil/src/ioGH.h" #include "CactusBase/IOUtil/src/ioutil_Utils.h" #include "CactusBase/IOUtil/src/ioutil_AdvertisedFiles.h" #include "CactusPUGH/PUGH/src/include/pugh.h" #include "ioHDF5GH.h" /* the rcs ID and its dummy funtion to use it */ static const char *rcsid = "$Header$"; CCTK_FILEVERSION(AlphaThorns_IOHDF5_Write_c) /******************************************************************** ******************** Internal Routines ************************ ********************************************************************/ static char *IOHDF5_GetFilename (const cGH *GH, int vindex, const ioHDF5Geo_t *slab, const char *name, int *is_new_file); /*@@ @routine IOHDF5_Write @date Tue Oct 10 2000 @author Thomas Radke @desc Opens the HDF5 output file, calls the dump routine, and closes it again. @enddesc @calls IOHDF5Util_DumpVar @var GH @vdesc Pointer to CCTK GH @vtype const cGH * @vio in @endvar @var vindex @vdesc index of variable @vtype 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 no storage was assigned to variable
-2 if filename couldn't be built from alias @endreturndesc @@*/ int IOHDF5_Write (const cGH *GH, int vindex, const char *alias) { ioGH *ioUtilGH; ioHDF5GH *myGH; hid_t file, plist; int is_new_file; char *filename; char *fullname; DECLARE_CCTK_PARAMETERS /* Get the handle for IO extensions */ ioUtilGH = (ioGH *) CCTK_GHExtension (GH, "IO"); myGH = (ioHDF5GH *) CCTK_GHExtension (GH, "IOHDF5"); /* check if variable has storage assigned */ if (! CCTK_QueryGroupStorageI (GH, CCTK_GroupIndexFromVarI (vindex))) { fullname = CCTK_FullName (vindex); CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING, "No IOHDF5 output for '%s' (no storage)", fullname); free (fullname); return (-1); } /* get the filename for output */ filename = IOHDF5_GetFilename (GH, vindex, myGH->out_geo[vindex], alias, &is_new_file); if (! filename) { fullname = CCTK_FullName (vindex); CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING, "Unable to construct file name for '%s'", fullname); free (fullname); return (-2); } /* open the output file on all IO processors or - in case of parallel HDF5 - on every processor */ #ifdef H5_HAVE_PARALLEL if (CCTK_MyProc (GH) != ioUtilGH->ioproc && ! ioUtilGH->unchunked) #else if (CCTK_MyProc (GH) != ioUtilGH->ioproc) #endif { file = -1; } else { if (verbose) { CCTK_VInfo (CCTK_THORNSTRING, "%s HDF5 output file '%s'", is_new_file ? "Opening" : "Appending", filename); } IOHDF5_ERROR (plist = H5Pcreate (H5P_FILE_ACCESS)); #ifdef CCTK_MPI #ifdef H5_HAVE_PARALLEL if (ioUtilGH->unchunked) { IOHDF5_ERROR (H5Pset_fapl_mpio (plist, PUGH_pGH (GH)->PUGH_COMM_WORLD, MPI_INFO_NULL)); } #endif #endif if (is_new_file) { IOHDF5_ERROR (file = H5Fcreate (filename, H5F_ACC_TRUNC, H5P_DEFAULT, plist)); } else { IOHDF5_ERROR (file = H5Fopen (filename, H5F_ACC_RDWR, plist)); } IOHDF5_ERROR (H5Pclose (plist)); } /* output global attributes */ if (is_new_file && file >= 0) { /* all GH extension variables and parameter stuff which is not specific to any dataset goes into dedicated groups */ if (out3D_parameters) { IOHDF5Util_DumpParameters (GH, file); } IOHDF5Util_DumpGHExtensions (GH, file); } /* output the data */ IOHDF5Util_DumpVar (GH, vindex, 0, myGH->out_geo[vindex], file, myGH->check_exisiting_objects[vindex]); /* close the file */ if (file >= 0) { if (verbose) { CCTK_INFO ("Closing HDF5 output file from this iteration"); } IOHDF5_ERROR (H5Fclose (file)); } /* free the filename if it was not registered for re-opening in IOHDF5_net3D_filename () */ if (out3D_septimefiles) { free (filename); } return (0); } /*@@ @routine IOHDF5_GetFilename @author Paul Walker @date Feb 1997 @desc Builds the filename for output. The names of all output files are stored in the filename database. The routine first searches in this database if there is already registered a filename for alias. If so, this name is returned. Otherwise it builds the filename from alias and stores it in the database. Generalized for Hyperslab extraction (GL) @enddesc @var GH @vdesc Pointer to CCTK GH @vtype const cGH * @vio in @endvar @var vindex @vdesc index of variable to output @vtype int @vio in @endvar @var slab @vdesc pointer to hyperslab structure @vtype const ioHDF5Geo_t * @vio in @endvar @var varname @vdesc alias name of variable to output @vtype const char * @vio in @endvar @var is_new_file @vdesc flag indicating if the file is to be created @vtype int @vio out @endvar @returntype char * @returndesc the allocated string containing the filename @endreturndesc @@*/ static char *IOHDF5_GetFilename (const cGH *GH, int vindex, const ioHDF5Geo_t *slab, const char *varname, int *is_new_file) { const ioGH *ioUtilGH; /* handle for IOUtil extensions */ ioHDF5GH *myGH; /* handle for IOHDF5 extensions */ const ioHDF5UtilGH *h5UtilGH; /* handle for IOHDF5Util extensions */ const pGH *pughGH; /* handle for PUGH extensions */ int myproc; /* FIXME: make these strings dynamic */ char extra[256]; /* Extra stuff in fname based on mode */ char extradir[256]; /* Extra stuff for an output dir */ char *filename; /* the return value */ int result; char *outputdir, *fullname; ioAdvertisedFileDesc advertised_file; #if 0 int idim; char *extrageo; /* Extra stuff for geometry information */ #endif char name[128]; DECLARE_CCTK_PARAMETERS /* get GH extensions for PUGH, IOUtil, IOHDF5Util, and IOHDF5 */ pughGH = (const pGH *) PUGH_pGH (GH); ioUtilGH = (const ioGH *) CCTK_GHExtension (GH, "IO"); myGH = (ioHDF5GH *) CCTK_GHExtension (GH, "IOHDF5"); h5UtilGH = (const ioHDF5UtilGH *) CCTK_GHExtension (GH, "IOHDF5Util"); #if 0 /*** FIXME: use new filenaming scheme ***/ /* To identify the slab in a volume (if sdimsdimvdim) { extrageo = (char*) malloc((slab->sdim+1)*sizeof(char)); sprintf(extrageo,"%d",slab->direction[0]); for (idim=1;idimsdim;idim++) sprintf(extrageo,"%s%d",extrageo,slab->direction[idim]); sprintf(name,"%s_s%s_%dd",varname,extrageo,slab->vdim); free(extrageo); } /* If sdim==vdim, make it simple: e.g. phi_3d */ else if (slab->sdim==slab->vdim) { sprintf(name,"%s_%dd",varname,slab->vdim); } else { CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING, "Inconsitent dimensions for >%s<: slab (%dD), variable (%dD)\n", varname, slab->sdim,slab->vdim); return(NULL); } #else slab = slab; strcpy (name, varname); #endif filename = (char *) GetNamedData (myGH->open_output_files, name); if (filename != NULL) { /* set flag to indicate that file should be opened in append mode */ *is_new_file = 0; return (filename); } extra[0] = '\0'; extradir[0]= '\0'; myproc = CCTK_MyProc (GH); if (out3D_septimefiles) { char *tmp = extra; sprintf (extra, "%s.time_%7.3f", extra, GH->cctk_time); /* And be sure to replace any spaces in the filename with an _ */ do if (*tmp == ' ') *tmp = '_'; while (*++tmp); } /* OUTPUT ONE FILE FOR EACH N PROCESSORS * ------------------------------------- * * If only one output file, the single file for each variable is written * in the normal output dir (that is extradir = ""). Otherwise * a directory is created for each output variable to hold the multiple * files. */ if (! ioUtilGH->unchunked && ioUtilGH->ioproc_every < CCTK_nProcs (GH)) { /* Add the output processor number to the extra string */ sprintf (extra, "%s.file_%d", extra, myproc / ioUtilGH->ioproc_every); /* If necessary create the output directory */ outputdir = (char *) malloc (strlen (myGH->outdir) + strlen (name) + 5); if (strcmp (myGH->outdir, ".")) { sprintf (outputdir, "%s/%s_3d", myGH->outdir, name); } else { sprintf (outputdir, "%s_3d", name); } result = IOUtil_CreateDirectory (GH, outputdir, ! CCTK_Equals (out3D_mode, "onefile"), ioUtilGH->ioproc); if (result < 0) { CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING, "Problem creating output directory '%s'", outputdir); } else if (result > 0 && CCTK_Equals (newverbose, "full")) { CCTK_VInfo (CCTK_THORNSTRING, "Output directory '%s' already exists", outputdir); } free (outputdir); #ifdef CCTK_MPI /* Wait for all processors to catch up */ CCTK_Barrier (GH); #endif /* extradir is the relative output directory */ sprintf (extradir, "%s_3d/", name); } /* CREATE THE COMPLETE OUTPUT FILENAME ----------------------------------- */ filename = (char *) malloc (strlen (myGH->outdir) + strlen (extradir) + strlen (name) + strlen (extra) + (pughGH->identity_string ? strlen (pughGH->identity_string) : 0) + 8); if (strcmp (myGH->outdir, ".")) { sprintf (filename, "%s/%s%s%s%s.h5", myGH->outdir, extradir, name, extra, (pughGH->identity_string ? pughGH->identity_string : "")); } else { sprintf (filename, "%s%s%s%s.h5", extradir, name, extra, (pughGH->identity_string ? pughGH->identity_string : "")); } /* no need to store filenames if used only once */ if (! out3D_septimefiles) { if (myproc == ioUtilGH->ioproc) { if (ioUtilGH->recovered) { IOHDF5_ERROR (H5Eset_auto (NULL, NULL)); *is_new_file = H5Fis_hdf5 (filename) <= 0; IOHDF5_ERROR (H5Eset_auto (h5UtilGH->print_error_fn, h5UtilGH->print_error_fn_arg)); if (! *is_new_file) { myGH->check_exisiting_objects[vindex] = 1; } } else { *is_new_file = 1; } } StoreNamedData (&myGH->open_output_files, name, filename); } else { *is_new_file = 1; } /* advertise the file for downloading */ fullname = CCTK_FullName (vindex); advertised_file.slice = ""; advertised_file.thorn = CCTK_THORNSTRING; advertised_file.varname = fullname; advertised_file.description = "Full-dimensional variable contents"; advertised_file.mimetype = "data/x-hdf5"; IOUtil_AdvertiseFile (GH, filename, &advertised_file); free (fullname); return (filename); }