/*@@ @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_AdvertisedFiles.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 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 return code of @seeroutine IOHDF5Util_DumpVar, 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, retval; char *filename, *fullname; DECLARE_CCTK_PARAMETERS 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, 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); } HDF5_ERROR (plist = H5Pcreate (H5P_FILE_ACCESS)); #ifdef CCTK_MPI #ifdef H5_HAVE_PARALLEL if (ioUtilGH->unchunked) { HDF5_ERROR (H5Pset_fapl_mpio (plist, PUGH_pGH (GH)->PUGH_COMM_WORLD, MPI_INFO_NULL)); } #endif #endif if (is_new_file) { HDF5_ERROR (file = H5Fcreate (filename, H5F_ACC_TRUNC, H5P_DEFAULT, plist)); } else { HDF5_ERROR (file = H5Fopen (filename, H5F_ACC_RDWR, plist)); } if (file < 0) { CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING, "Couldn't %s IOHDF5 output file '%s'", is_new_file ? "create" : "open", filename); } HDF5_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 (strcmp (out3D_parameters, "no")) { IOHDF5Util_DumpParameters (GH, ! strcmp (out3D_parameters, "all"), file); } IOHDF5Util_DumpGHExtensions (GH, file); } /* output the data */ retval = IOHDF5Util_DumpVar (GH, myGH->requests[vindex], file); /* close the file */ if (file >= 0) { if (verbose) { CCTK_INFO ("Closing HDF5 output file from this iteration"); } HDF5_ERROR (H5Fclose (file)); } /* free the filename if it was not registered for re-opening in IOHDF5_net3D_filename () */ if (out3D_septimefiles) { free (filename); } return (retval); } /*@@ @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 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 char *varname, int *is_new_file) { const ioGH *ioUtilGH; ioHDF5GH *myGH; int myproc, result; /* FIXME: make these strings dynamic */ char extra[256], extradir[256]; char *filename, *outputdir, *fullname, *tmp; ioAdvertisedFileDesc advertised_file; DECLARE_CCTK_PARAMETERS /* get GH extensions for IOUtil and IOHDF5 */ ioUtilGH = (const ioGH *) CCTK_GHExtension (GH, "IO"); myGH = (ioHDF5GH *) CCTK_GHExtension (GH, "IOHDF5"); filename = (char *) GetNamedData (myGH->open_output_files, varname); 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) { 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 (varname) + 5); if (strcmp (myGH->outdir, ".")) { sprintf (outputdir, "%s/%s_3d", myGH->outdir, varname); } else { sprintf (outputdir, "%s_3d", varname); } 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/", varname); } /* CREATE THE COMPLETE OUTPUT FILENAME ----------------------------------- */ filename = (char *) malloc (strlen (myGH->outdir) + strlen (extradir) + strlen (varname) + strlen (extra) + strlen (GH->identity) + 8); if (strcmp (myGH->outdir, ".")) { sprintf (filename, "%s/%s%s%s%s.h5", myGH->outdir, extradir, varname, extra, GH->identity); } else { sprintf (filename, "%s%s%s%s.h5", extradir, varname, extra, GH->identity); } /* no need to store filenames if used only once */ if (! out3D_septimefiles) { if (myproc == ioUtilGH->ioproc) { if (ioUtilGH->recovered) { H5E_BEGIN_TRY { *is_new_file = H5Fis_hdf5 (filename) <= 0; } H5E_END_TRY; } else { *is_new_file = 1; } } StoreNamedData (&myGH->open_output_files, varname, 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); }