00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 #include <set>
00041 #include <cstring>
00042 #include <boost/scoped_array.hpp>
00043
00044 #include "Hdf5DataWriter.hpp"
00045
00046 #include "Exception.hpp"
00047 #include "OutputFileHandler.hpp"
00048 #include "PetscTools.hpp"
00049 #include "Version.hpp"
00050 #include "MathsCustomFunctions.hpp"
00051
00052 Hdf5DataWriter::Hdf5DataWriter(DistributedVectorFactory& rVectorFactory,
00053 const std::string& rDirectory,
00054 const std::string& rBaseName,
00055 bool cleanDirectory,
00056 bool extendData,
00057 std::string datasetName)
00058 : AbstractHdf5Access(rDirectory, rBaseName, datasetName),
00059 mrVectorFactory(rVectorFactory),
00060 mCleanDirectory(cleanDirectory),
00061 mUseExistingFile(extendData),
00062 mIsInDefineMode(true),
00063 mIsFixedDimensionSet(false),
00064 mEstimatedUnlimitedLength(1u),
00065 mFileFixedDimensionSize(0u),
00066 mDataFixedDimensionSize(0u),
00067 mLo(mrVectorFactory.GetLow()),
00068 mHi(mrVectorFactory.GetHigh()),
00069 mNumberOwned(0u),
00070 mOffset(0u),
00071 mNeedExtend(false),
00072 mUseMatrixForIncompleteData(false),
00073 mCurrentTimeStep(0),
00074 mSinglePermutation(NULL),
00075 mDoublePermutation(NULL),
00076 mSingleIncompleteOutputMatrix(NULL),
00077 mDoubleIncompleteOutputMatrix(NULL),
00078 mUseOptimalChunkSizeAlgorithm(true),
00079 mNumberOfChunks(0u)
00080 {
00081 mChunkSize[0] = 0;
00082 mChunkSize[1] = 0;
00083 mChunkSize[2] = 0;
00084 mFixedChunkSize[0] = 0;
00085 mFixedChunkSize[1] = 0;
00086 mFixedChunkSize[2] = 0;
00087
00088 if (mUseExistingFile && mCleanDirectory)
00089 {
00090 EXCEPTION("You are asking to delete a file and then extend it, change arguments to constructor.");
00091 }
00092
00093 if (!mUseExistingFile && mDatasetName != "Data")
00094 {
00095
00096 EXCEPTION("Adding new data only makes sense when extending an existing file");
00097 }
00098
00099 if (mUseExistingFile)
00100 {
00101
00102 mIsInDefineMode = false;
00103
00104
00105 OpenFile();
00106
00107
00108
00109 if (!DoesDatasetExist(mDatasetName))
00110 {
00111
00112 H5Fclose(mFileId);
00113 mIsInDefineMode = true;
00114 }
00115
00116 else
00117 {
00118
00119 assert(mCleanDirectory==false);
00120
00121 mVariablesDatasetId = H5Dopen(mFileId, mDatasetName.c_str());
00122 hid_t variables_dataspace = H5Dget_space(mVariablesDatasetId);
00123
00124 hsize_t dataset_max_sizes[DATASET_DIMS];
00125 H5Sget_simple_extent_dims(variables_dataspace, mDatasetDims, dataset_max_sizes);
00126 H5Sclose(variables_dataspace);
00127
00128
00129 if (dataset_max_sizes[0] != H5S_UNLIMITED)
00130 {
00131 H5Dclose(mVariablesDatasetId);
00132 H5Fclose(mFileId);
00133 EXCEPTION("Tried to open a datafile for extending which doesn't have an unlimited dimension.");
00134 }
00135 mIsUnlimitedDimensionSet = true;
00136
00137
00138 for (unsigned i=1; i<DATASET_DIMS; i++)
00139 {
00140 assert(mDatasetDims[i] == dataset_max_sizes[i]);
00141 }
00142 mFileFixedDimensionSize = mDatasetDims[1];
00143 mIsFixedDimensionSet = true;
00144 mVariables.reserve(mDatasetDims[2]);
00145
00146
00147 hid_t attribute_id = H5Aopen_name(mVariablesDatasetId, "Variable Details");
00148 hid_t attribute_type = H5Aget_type(attribute_id);
00149 hid_t attribute_space = H5Aget_space(attribute_id);
00150 hsize_t attr_dataspace_dim;
00151 H5Sget_simple_extent_dims(attribute_space, &attr_dataspace_dim, NULL);
00152 unsigned num_columns = H5Sget_simple_extent_npoints(attribute_space);
00153 assert(num_columns == mDatasetDims[2]);
00154
00155 char* string_array = (char *)malloc(sizeof(char)*MAX_STRING_SIZE*(int)num_columns);
00156 H5Aread(attribute_id, attribute_type, string_array);
00157
00158
00159 for (unsigned index=0; index<num_columns; index++)
00160 {
00161
00162 std::string column_name_unit(&string_array[MAX_STRING_SIZE*index]);
00163
00164
00165 size_t name_length = column_name_unit.find('(');
00166 size_t unit_length = column_name_unit.find(')') - name_length - 1;
00167
00168
00169 DataWriterVariable var;
00170 var.mVariableName = column_name_unit.substr(0, name_length);
00171 var.mVariableUnits = column_name_unit.substr(name_length+1, unit_length);
00172 mVariables.push_back(var);
00173 }
00174
00175
00176 free(string_array);
00177 H5Tclose(attribute_type);
00178 H5Sclose(attribute_space);
00179 H5Aclose(attribute_id);
00180
00181
00182 SetUnlimitedDatasetId();
00183
00184
00185 hid_t timestep_dataspace = H5Dget_space(mUnlimitedDatasetId);
00186 hsize_t num_timesteps;
00187 H5Sget_simple_extent_dims(timestep_dataspace, &num_timesteps, NULL);
00188 H5Sclose(timestep_dataspace);
00189 mCurrentTimeStep = (long)num_timesteps - 1;
00190
00191
00192 attribute_id = H5Aopen_name(mVariablesDatasetId, "IsDataComplete");
00193 if (attribute_id < 0)
00194 {
00195 #define COVERAGE_IGNORE
00196
00197 EXCEPTION("Extending old-format files isn't supported.");
00198 #undef COVERAGE_IGNORE
00199 }
00200 else
00201 {
00202 attribute_type = H5Aget_type(attribute_id);
00203 attribute_space = H5Aget_space(attribute_id);
00204 unsigned is_data_complete;
00205 H5Aread(attribute_id, H5T_NATIVE_UINT, &is_data_complete);
00206 mIsDataComplete = (is_data_complete == 1) ? true : false;
00207 H5Tclose(attribute_type);
00208 H5Sclose(attribute_space);
00209 H5Aclose(attribute_id);
00210 }
00211 if (mIsDataComplete)
00212 {
00213 mNumberOwned = mrVectorFactory.GetLocalOwnership();
00214 mOffset = mLo;
00215 mDataFixedDimensionSize = mFileFixedDimensionSize;
00216 }
00217 else
00218 {
00219
00220 attribute_id = H5Aopen_name(mVariablesDatasetId, "NodeMap");
00221 attribute_type = H5Aget_type(attribute_id);
00222 attribute_space = H5Aget_space(attribute_id);
00223
00224
00225 unsigned num_node_indices = H5Sget_simple_extent_npoints(attribute_space);
00226
00227
00228 mIncompleteNodeIndices.clear();
00229 mIncompleteNodeIndices.resize(num_node_indices);
00230 H5Aread(attribute_id, H5T_NATIVE_UINT, &mIncompleteNodeIndices[0]);
00231
00232
00233 H5Tclose(attribute_type);
00234 H5Sclose(attribute_space);
00235 H5Aclose(attribute_id);
00236
00237
00238 mNumberOwned = mrVectorFactory.GetLocalOwnership();
00239 ComputeIncompleteOffset();
00243 mDataFixedDimensionSize = UINT_MAX;
00244 H5Dclose(mVariablesDatasetId);
00245 H5Dclose(mUnlimitedDatasetId);
00246 H5Fclose(mFileId);
00247 EXCEPTION("Unable to extend an incomplete data file at present.");
00248 }
00249
00250
00251 AdvanceAlongUnlimitedDimension();
00252 }
00253 }
00254 }
00255
00256 Hdf5DataWriter::~Hdf5DataWriter()
00257 {
00258 Close();
00259
00260 if (mSinglePermutation)
00261 {
00262 PetscTools::Destroy(mSinglePermutation);
00263 }
00264 if (mDoublePermutation)
00265 {
00266 PetscTools::Destroy(mDoublePermutation);
00267 }
00268 if (mSingleIncompleteOutputMatrix)
00269 {
00270 PetscTools::Destroy(mSingleIncompleteOutputMatrix);
00271 }
00272 if (mDoubleIncompleteOutputMatrix)
00273 {
00274 PetscTools::Destroy(mDoubleIncompleteOutputMatrix);
00275 }
00276 }
00277
00278 void Hdf5DataWriter::OpenFile()
00279 {
00280 OutputFileHandler output_file_handler(mDirectory, mCleanDirectory);
00281 std::string file_name = mDirectory.GetAbsolutePath() + mBaseName + ".h5";
00282
00283 if (mUseExistingFile)
00284 {
00285 FileFinder h5_file(file_name, RelativeTo::Absolute);
00286 if (!h5_file.Exists())
00287 {
00288 EXCEPTION("Hdf5DataWriter could not open " + file_name + " , as it does not exist.");
00289 }
00290 }
00291
00292
00293 hid_t fapl = H5Pcreate(H5P_FILE_ACCESS);
00294 H5Pset_fapl_mpio(fapl, PETSC_COMM_WORLD, MPI_INFO_NULL);
00295
00296
00297 mDatasetDims[0] = mEstimatedUnlimitedLength;
00298 mDatasetDims[1] = mFileFixedDimensionSize;
00299 mDatasetDims[2] = mVariables.size();
00300
00301
00302 std::string attempting_to;
00303 if (mUseExistingFile)
00304 {
00305 mFileId = H5Fopen(file_name.c_str(), H5F_ACC_RDWR, fapl);
00306 attempting_to = "open";
00307 }
00308 else
00309 {
00310
00311
00312 SetChunkSize();
00313 hid_t fcpl = H5Pcreate(H5P_FILE_CREATE);
00314 if (mNumberOfChunks>64)
00315 {
00316 H5Pset_istore_k(fcpl, (mNumberOfChunks+1)/2);
00317 }
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344 mFileId = H5Fcreate(file_name.c_str(), H5F_ACC_TRUNC, fcpl, fapl);
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359 attempting_to = "create";
00360 H5Pclose(fcpl);
00361 }
00362
00363 H5Pclose(fapl);
00364
00365 if (mFileId < 0)
00366 {
00367 mVariablesDatasetId = 0;
00368 EXCEPTION("Hdf5DataWriter could not " << attempting_to << " " << file_name <<
00369 " , H5F" << attempting_to << " error code = " << mFileId);
00370 }
00371 }
00372
00373 void Hdf5DataWriter::DefineFixedDimension(long dimensionSize)
00374 {
00375 if (!mIsInDefineMode)
00376 {
00377 EXCEPTION("Cannot define variables when not in Define mode");
00378 }
00379 if (dimensionSize < 1)
00380 {
00381 EXCEPTION("Fixed dimension must be at least 1 long");
00382 }
00383 if (mIsFixedDimensionSet)
00384 {
00385 EXCEPTION("Fixed dimension already set");
00386 }
00387
00388
00389 mLo = mrVectorFactory.GetLow();
00390 mHi = mrVectorFactory.GetHigh();
00391 mNumberOwned = mrVectorFactory.GetLocalOwnership();
00392 mOffset = mLo;
00393 mFileFixedDimensionSize = dimensionSize;
00394 mDataFixedDimensionSize = dimensionSize;
00395 mIsFixedDimensionSet = true;
00396 }
00397
00398 void Hdf5DataWriter::DefineFixedDimension(const std::vector<unsigned>& rNodesToOuput, long vecSize)
00399 {
00400 unsigned vector_size = rNodesToOuput.size();
00401
00402 for (unsigned index=0; index < vector_size-1; index++)
00403 {
00404 if (rNodesToOuput[index] >= rNodesToOuput[index+1])
00405 {
00406 EXCEPTION("Input should be monotonic increasing");
00407 }
00408 }
00409
00410 if ((int) rNodesToOuput.back() >= vecSize)
00411 {
00412 EXCEPTION("Vector size doesn't match nodes to output");
00413 }
00414
00415 DefineFixedDimension(vecSize);
00416
00417 mFileFixedDimensionSize = vector_size;
00418 mIsDataComplete = false;
00419 mIncompleteNodeIndices = rNodesToOuput;
00420 ComputeIncompleteOffset();
00421 }
00422
00423 void Hdf5DataWriter::DefineFixedDimensionUsingMatrix(const std::vector<unsigned>& rNodesToOuput, long vecSize)
00424 {
00425 unsigned vector_size = rNodesToOuput.size();
00426
00427 for (unsigned index=0; index < vector_size-1; index++)
00428 {
00429 if (rNodesToOuput[index] >= rNodesToOuput[index+1])
00430 {
00431 EXCEPTION("Input should be monotonic increasing");
00432 }
00433 }
00434
00435 if ((int) rNodesToOuput.back() >= vecSize)
00436 {
00437 EXCEPTION("Vector size doesn't match nodes to output");
00438 }
00439
00440 DefineFixedDimension(vecSize);
00441
00442 mFileFixedDimensionSize = vector_size;
00443 mIsDataComplete = false;
00444 mIncompleteNodeIndices = rNodesToOuput;
00445 mUseMatrixForIncompleteData = true;
00446 ComputeIncompleteOffset();
00447
00448
00449 assert(mSingleIncompleteOutputMatrix == NULL);
00450 assert(mDoubleIncompleteOutputMatrix == NULL);
00451 PetscTools::SetupMat(mSingleIncompleteOutputMatrix, mFileFixedDimensionSize, mDataFixedDimensionSize, 2, mNumberOwned, mHi - mLo);
00452 PetscTools::SetupMat(mDoubleIncompleteOutputMatrix, 2*mFileFixedDimensionSize, 2*mDataFixedDimensionSize, 4, 2*mNumberOwned, 2*(mHi - mLo));
00453
00454
00455 for (unsigned row_index = mOffset; row_index < mOffset + mNumberOwned; row_index++)
00456 {
00457
00458 MatSetValue(mSingleIncompleteOutputMatrix, row_index, row_index, 0.0, INSERT_VALUES);
00459
00460
00461 MatSetValue(mSingleIncompleteOutputMatrix, row_index, rNodesToOuput[row_index], 1.0, INSERT_VALUES);
00462
00463 unsigned bi_index = 2*row_index;
00464 unsigned perm_index = 2*rNodesToOuput[row_index];
00465
00466
00467 MatSetValue(mDoubleIncompleteOutputMatrix, bi_index, bi_index, 0.0, INSERT_VALUES);
00468 MatSetValue(mDoubleIncompleteOutputMatrix, bi_index+1, bi_index+1, 0.0, INSERT_VALUES);
00469
00470
00471 MatSetValue(mDoubleIncompleteOutputMatrix, bi_index, perm_index, 1.0, INSERT_VALUES);
00472 MatSetValue(mDoubleIncompleteOutputMatrix, bi_index+1, perm_index+1, 1.0, INSERT_VALUES);
00473 }
00474 MatAssemblyBegin(mSingleIncompleteOutputMatrix, MAT_FINAL_ASSEMBLY);
00475 MatAssemblyBegin(mDoubleIncompleteOutputMatrix, MAT_FINAL_ASSEMBLY);
00476 MatAssemblyEnd(mSingleIncompleteOutputMatrix, MAT_FINAL_ASSEMBLY);
00477 MatAssemblyEnd(mDoubleIncompleteOutputMatrix, MAT_FINAL_ASSEMBLY);
00478
00479
00480 }
00481
00482 void Hdf5DataWriter::ComputeIncompleteOffset()
00483 {
00484 mOffset = 0;
00485 mNumberOwned = 0;
00486 for (unsigned i=0; i<mIncompleteNodeIndices.size(); i++)
00487 {
00488 if (mIncompleteNodeIndices[i] < mLo)
00489 {
00490 mOffset++;
00491 }
00492 else if (mIncompleteNodeIndices[i] < mHi)
00493 {
00494 mNumberOwned++;
00495 }
00496 }
00497 }
00498
00499 int Hdf5DataWriter::DefineVariable(const std::string& rVariableName,
00500 const std::string& rVariableUnits)
00501 {
00502 if (!mIsInDefineMode)
00503 {
00504 EXCEPTION("Cannot define variables when not in Define mode");
00505 }
00506
00507 CheckVariableName(rVariableName);
00508 CheckUnitsName(rVariableUnits);
00509
00510
00511 for (unsigned index=0; index<mVariables.size(); index++)
00512 {
00513 if (mVariables[index].mVariableName == rVariableName)
00514 {
00515 EXCEPTION("Variable name already exists");
00516 }
00517 }
00518
00519 DataWriterVariable new_variable;
00520 new_variable.mVariableName = rVariableName;
00521 new_variable.mVariableUnits = rVariableUnits;
00522 int variable_id;
00523
00524
00525 mVariables.push_back(new_variable);
00526
00527
00528
00529 variable_id = mVariables.size() - 1;
00530
00531 return variable_id;
00532 }
00533
00534 void Hdf5DataWriter::CheckVariableName(const std::string& rName)
00535 {
00536 if (rName.length() == 0)
00537 {
00538 EXCEPTION("Variable name not allowed: may not be blank.");
00539 }
00540 CheckUnitsName(rName);
00541 }
00542
00543 void Hdf5DataWriter::CheckUnitsName(const std::string& rName)
00544 {
00545 for (unsigned i=0; i<rName.length(); i++)
00546 {
00547 if (!isalnum(rName[i]) && !(rName[i]=='_'))
00548 {
00549 std::string error = "Variable name/units '" + rName + "' not allowed: may only contain alphanumeric characters or '_'.";
00550 EXCEPTION(error);
00551 }
00552 }
00553 }
00554
00555 void Hdf5DataWriter::EndDefineMode()
00556 {
00557
00558 if (mVariables.size() < 1)
00559 {
00560 EXCEPTION("Cannot end define mode. No variables have been defined.");
00561 }
00562
00563
00564 if (mIsFixedDimensionSet == false)
00565 {
00566 EXCEPTION("Cannot end define mode. One fixed dimension should be defined.");
00567 }
00568
00569 OpenFile();
00570
00571 mIsInDefineMode = false;
00572
00573
00574
00575
00576
00577
00578 hsize_t dataset_max_dims[DATASET_DIMS];
00579 if (mIsUnlimitedDimensionSet)
00580 {
00581 dataset_max_dims[0] = H5S_UNLIMITED;
00582 }
00583 else
00584 {
00585 dataset_max_dims[0] = 1;
00586 }
00587 dataset_max_dims[1] = mDatasetDims[1];
00588 dataset_max_dims[2] = mDatasetDims[2];
00589
00590
00591 if (mNumberOfChunks==0)
00592 {
00593 SetChunkSize();
00594 }
00595
00596
00597 hid_t cparms = H5Pcreate (H5P_DATASET_CREATE);
00598 H5Pset_chunk( cparms, DATASET_DIMS, mChunkSize);
00599 hid_t filespace = H5Screate_simple(DATASET_DIMS, mDatasetDims, dataset_max_dims);
00600 mVariablesDatasetId = H5Dcreate(mFileId, mDatasetName.c_str(), H5T_NATIVE_DOUBLE, filespace, cparms);
00601 SetMainDatasetRawChunkCache();
00602 H5Sclose(filespace);
00603 H5Pclose(cparms);
00604
00605
00606 const unsigned MAX_STRING_SIZE = 100;
00607 hsize_t columns[1] = {mVariables.size()};
00608 hid_t colspace = H5Screate_simple(1, columns, NULL);
00609
00610
00611 char* col_data = (char*) malloc(mVariables.size() * sizeof(char) * MAX_STRING_SIZE);
00612
00613 char* col_data_offset = col_data;
00614 for (unsigned var=0; var<mVariables.size(); var++)
00615 {
00616 std::string full_name = mVariables[var].mVariableName + "(" + mVariables[var].mVariableUnits + ")";
00617 strcpy (col_data_offset, full_name.c_str());
00618 col_data_offset += sizeof(char) * MAX_STRING_SIZE;
00619 }
00620
00621
00622 hid_t string_type = H5Tcopy(H5T_C_S1);
00623 H5Tset_size(string_type, MAX_STRING_SIZE );
00624 hid_t attr = H5Acreate(mVariablesDatasetId, "Variable Details", string_type, colspace, H5P_DEFAULT);
00625
00626
00627 H5Awrite(attr, string_type, col_data);
00628
00629
00630 free(col_data);
00631 H5Sclose(colspace);
00632 H5Aclose(attr);
00633
00634
00635 columns[0] = 1;
00636 colspace = H5Screate_simple(1, columns, NULL);
00637 attr = H5Acreate(mVariablesDatasetId, "IsDataComplete", H5T_NATIVE_UINT, colspace, H5P_DEFAULT);
00638
00639
00640 unsigned is_data_complete = mIsDataComplete ? 1 : 0;
00641 H5Awrite(attr, H5T_NATIVE_UINT, &is_data_complete);
00642
00643 H5Sclose(colspace);
00644 H5Aclose(attr);
00645
00646 if (!mIsDataComplete)
00647 {
00648
00649
00650 columns[0] = mFileFixedDimensionSize;
00651 colspace = H5Screate_simple(1, columns, NULL);
00652 attr = H5Acreate(mVariablesDatasetId, "NodeMap", H5T_NATIVE_UINT, colspace, H5P_DEFAULT);
00653
00654
00655 H5Awrite(attr, H5T_NATIVE_UINT, &mIncompleteNodeIndices[0]);
00656
00657 H5Sclose(colspace);
00658 H5Aclose(attr);
00659 }
00660
00661
00662
00663
00664 if (mIsUnlimitedDimensionSet)
00665 {
00666 hsize_t time_dataset_dims[1] = {mEstimatedUnlimitedLength};
00667 hsize_t time_dataset_max_dims[1] = {H5S_UNLIMITED};
00668
00669
00670
00671
00672
00673 hsize_t time_chunk_dims[1] = {128u};
00674 hid_t time_cparms = H5Pcreate (H5P_DATASET_CREATE);
00675 H5Pset_chunk( time_cparms, 1, time_chunk_dims);
00676
00677 hid_t time_filespace = H5Screate_simple(1, time_dataset_dims, time_dataset_max_dims);
00678
00679
00680
00681
00682
00683
00684
00685
00686 mUnlimitedDatasetId = H5Dcreate(mFileId, (mDatasetName + "_Unlimited").c_str(), H5T_NATIVE_DOUBLE, time_filespace, time_cparms);
00687
00688
00689 hsize_t one = 1;
00690 hid_t one_column_space = H5Screate_simple(1, &one, NULL);
00691
00692
00693 hid_t unit_attr = H5Acreate(mUnlimitedDatasetId, "Unit", string_type, one_column_space, H5P_DEFAULT);
00694
00695
00696 hid_t name_attr = H5Acreate(mUnlimitedDatasetId, "Name", string_type, one_column_space, H5P_DEFAULT);
00697
00698
00699 char unit_string[MAX_STRING_SIZE];
00700 strcpy(unit_string, mUnlimitedDimensionUnit.c_str());
00701 H5Awrite(unit_attr, string_type, unit_string);
00702
00703
00704 char name_string[MAX_STRING_SIZE];
00705 strcpy(name_string, mUnlimitedDimensionName.c_str());
00706 H5Awrite(name_attr, string_type, name_string);
00707
00708
00709 H5Pclose(time_cparms);
00710 H5Sclose(one_column_space);
00711 H5Aclose(unit_attr);
00712 H5Aclose(name_attr);
00713 H5Sclose(time_filespace);
00714 }
00715
00716
00717
00718
00719
00720
00721 const unsigned MAX_PROVENANCE_STRING_SIZE = 1023;
00722 hid_t long_string_type = H5Tcopy(H5T_C_S1);
00723 H5Tset_size(long_string_type, MAX_PROVENANCE_STRING_SIZE );
00724 hsize_t prov_columns[1] = {1};
00725 hid_t provenance_space = H5Screate_simple(1, prov_columns, NULL);
00726 char* provenance_data = (char*) malloc(sizeof(char) * MAX_PROVENANCE_STRING_SIZE);
00727 assert( ChasteBuildInfo::GetProvenanceString().length() < MAX_PROVENANCE_STRING_SIZE);
00728
00729 strcpy(provenance_data, ChasteBuildInfo::GetProvenanceString().c_str());
00730 hid_t prov_attr = H5Acreate(mVariablesDatasetId, "Chaste Provenance", long_string_type, provenance_space, H5P_DEFAULT);
00731
00732
00733 H5Awrite(prov_attr, long_string_type, provenance_data);
00734
00735
00736 free(provenance_data);
00737 H5Sclose(provenance_space);
00738 H5Aclose(prov_attr);
00739 }
00740
00741 void Hdf5DataWriter::PutVector(int variableID, Vec petscVector)
00742 {
00743 if (mIsInDefineMode)
00744 {
00745 EXCEPTION("Cannot write data while in define mode.");
00746 }
00747
00748 int vector_size;
00749 VecGetSize(petscVector, &vector_size);
00750
00751 if ((unsigned) vector_size != mDataFixedDimensionSize)
00752 {
00753 EXCEPTION("Vector size doesn't match fixed dimension");
00754 }
00755
00756
00757 PossiblyExtend();
00758
00759 Vec output_petsc_vector;
00760
00761
00762 if (mSinglePermutation == NULL)
00763 {
00764
00765 output_petsc_vector = petscVector;
00766 }
00767 else
00768 {
00769 assert(mIsDataComplete);
00770
00771 VecDuplicate(petscVector, &output_petsc_vector);
00772
00773
00774 MatMult(mSinglePermutation, petscVector, output_petsc_vector);
00775 }
00776
00777
00778 hid_t memspace=0;
00779 if (mNumberOwned != 0)
00780 {
00781 hsize_t v_size[1] = {mNumberOwned};
00782 memspace = H5Screate_simple(1, v_size, NULL);
00783 }
00784
00785
00786 hsize_t count[DATASET_DIMS] = {1, mNumberOwned, 1};
00787 hsize_t offset_dims[DATASET_DIMS] = {mCurrentTimeStep, mOffset, (unsigned)(variableID)};
00788 hid_t file_dataspace = H5Dget_space(mVariablesDatasetId);
00789
00790
00791 hid_t property_list_id = H5Pcreate(H5P_DATASET_XFER);
00792 H5Pset_dxpl_mpio(property_list_id, H5FD_MPIO_COLLECTIVE);
00793
00794 H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, offset_dims, NULL, count, NULL);
00795
00796 double* p_petsc_vector;
00797 VecGetArray(output_petsc_vector, &p_petsc_vector);
00798
00799 if (mIsDataComplete)
00800 {
00801 H5Dwrite(mVariablesDatasetId, H5T_NATIVE_DOUBLE, memspace, file_dataspace, property_list_id, p_petsc_vector);
00802 }
00803 else
00804 {
00805 if (mUseMatrixForIncompleteData)
00806 {
00807
00808 output_petsc_vector = PetscTools::CreateVec(mFileFixedDimensionSize, mNumberOwned);
00809
00810
00811 MatMult(mSingleIncompleteOutputMatrix, petscVector, output_petsc_vector);
00812
00813 double* p_petsc_vector_incomplete;
00814 VecGetArray(output_petsc_vector, &p_petsc_vector_incomplete);
00815 H5Dwrite(mVariablesDatasetId, H5T_NATIVE_DOUBLE, memspace, file_dataspace, property_list_id, p_petsc_vector_incomplete);
00816 }
00817 else
00818 {
00819
00820 boost::scoped_array<double> local_data(new double[mNumberOwned]);
00821 for (unsigned i=0; i<mNumberOwned; i++)
00822 {
00823 local_data[i] = p_petsc_vector[ mIncompleteNodeIndices[mOffset+i]-mLo ];
00824
00825 }
00826 H5Dwrite(mVariablesDatasetId, H5T_NATIVE_DOUBLE, memspace, file_dataspace, property_list_id, local_data.get());
00827 }
00828 }
00829
00830 VecRestoreArray(output_petsc_vector, &p_petsc_vector);
00831
00832 H5Pclose(property_list_id);
00833 H5Sclose(file_dataspace);
00834 if (mNumberOwned !=0)
00835 {
00836 H5Sclose(memspace);
00837 }
00838
00839 if (petscVector != output_petsc_vector)
00840 {
00841
00842 PetscTools::Destroy(output_petsc_vector);
00843 }
00844 }
00845
00846 void Hdf5DataWriter::PutStripedVector(std::vector<int> variableIDs, Vec petscVector)
00847 {
00848 if (mIsInDefineMode)
00849 {
00850 EXCEPTION("Cannot write data while in define mode.");
00851 }
00852
00853 if (variableIDs.size() <= 1)
00854 {
00855 EXCEPTION("The PutStripedVector method requires at least two variables ID. If only one is needed, use PutVector method instead");
00856 }
00857
00858 const unsigned NUM_STRIPES=variableIDs.size();
00859
00860 int firstVariableID=variableIDs[0];
00861
00862
00863 for (unsigned i = 1; i < variableIDs.size(); i++)
00864 {
00865 if (variableIDs[i]-variableIDs[i-1] != 1)
00866 {
00867 EXCEPTION("Columns should be consecutive. Try reordering them.");
00868 }
00869 }
00870
00871 int vector_size;
00872 VecGetSize(petscVector, &vector_size);
00873
00874 if ((unsigned) vector_size != NUM_STRIPES*mDataFixedDimensionSize)
00875 {
00876 EXCEPTION("Vector size doesn't match fixed dimension");
00877 }
00878
00879
00880 PossiblyExtend();
00881
00882 Vec output_petsc_vector;
00883
00884
00885 if (mDoublePermutation == NULL)
00886 {
00887
00888 output_petsc_vector = petscVector;
00889 }
00890 else
00891 {
00892 assert(mIsDataComplete);
00893
00894 VecDuplicate(petscVector, &output_petsc_vector);
00895
00896
00897 MatMult(mDoublePermutation, petscVector, output_petsc_vector);
00898 }
00899
00900 hid_t memspace=0;
00901 if (mNumberOwned !=0)
00902 {
00903 hsize_t v_size[1] = {mNumberOwned*NUM_STRIPES};
00904 memspace = H5Screate_simple(1, v_size, NULL);
00905 }
00906
00907
00908 hsize_t start[DATASET_DIMS] = {mCurrentTimeStep, mOffset, (unsigned)(firstVariableID)};
00909 hsize_t stride[DATASET_DIMS] = {1, 1, 1};
00910 hsize_t block_size[DATASET_DIMS] = {1, mNumberOwned, 1};
00911 hsize_t number_blocks[DATASET_DIMS] = {1, 1, NUM_STRIPES};
00912
00913 hid_t hyperslab_space = H5Dget_space(mVariablesDatasetId);
00914 H5Sselect_hyperslab(hyperslab_space, H5S_SELECT_SET, start, stride, number_blocks, block_size);
00915
00916
00917 hid_t property_list_id = H5Pcreate(H5P_DATASET_XFER);
00918 H5Pset_dxpl_mpio(property_list_id, H5FD_MPIO_COLLECTIVE);
00919
00920 double* p_petsc_vector;
00921 VecGetArray(output_petsc_vector, &p_petsc_vector);
00922
00923 if (mIsDataComplete)
00924 {
00925 H5Dwrite(mVariablesDatasetId, H5T_NATIVE_DOUBLE, memspace, hyperslab_space, property_list_id, p_petsc_vector);
00926 }
00927 else
00928 {
00929 if (variableIDs.size() < 3)
00930 {
00931 if (mUseMatrixForIncompleteData)
00932 {
00933
00934 output_petsc_vector = PetscTools::CreateVec(2*mFileFixedDimensionSize, 2*mNumberOwned);
00935
00936
00937 MatMult(mDoubleIncompleteOutputMatrix, petscVector, output_petsc_vector);
00938
00939 double* p_petsc_vector_incomplete;
00940 VecGetArray(output_petsc_vector, &p_petsc_vector_incomplete);
00941
00942 H5Dwrite(mVariablesDatasetId, H5T_NATIVE_DOUBLE, memspace, hyperslab_space, property_list_id, p_petsc_vector_incomplete);
00943 }
00944 else
00945 {
00946
00947 boost::scoped_array<double> local_data(new double[mNumberOwned*NUM_STRIPES]);
00948 for (unsigned i=0; i<mNumberOwned; i++)
00949 {
00950 unsigned local_node_number = mIncompleteNodeIndices[mOffset+i] - mLo;
00951 local_data[NUM_STRIPES*i] = p_petsc_vector[ local_node_number*NUM_STRIPES ];
00952 local_data[NUM_STRIPES*i+1] = p_petsc_vector[ local_node_number*NUM_STRIPES + 1];
00953 }
00954
00955 H5Dwrite(mVariablesDatasetId, H5T_NATIVE_DOUBLE, memspace, hyperslab_space, property_list_id, local_data.get());
00956 }
00957 }
00958 else
00959 {
00960 EXCEPTION("The PutStripedVector functionality for incomplete data is supported for only 2 stripes");
00961 }
00962 }
00963
00964 VecRestoreArray(output_petsc_vector, &p_petsc_vector);
00965
00966 H5Sclose(hyperslab_space);
00967 if (mNumberOwned != 0)
00968 {
00969 H5Sclose(memspace);
00970 }
00971 H5Pclose(property_list_id);
00972
00973 if (petscVector != output_petsc_vector)
00974 {
00975
00976 PetscTools::Destroy(output_petsc_vector);
00977 }
00978 }
00979
00980 void Hdf5DataWriter::PutUnlimitedVariable(double value)
00981 {
00982 if (mIsInDefineMode)
00983 {
00984 EXCEPTION("Cannot write data while in define mode.");
00985 }
00986
00987 if (!mIsUnlimitedDimensionSet)
00988 {
00989 EXCEPTION("PutUnlimitedVariable() called but no unlimited dimension has been set");
00990 }
00991
00992
00993 PossiblyExtend();
00994
00995
00996 if (!PetscTools::AmMaster())
00997 {
00998 return;
00999 }
01000
01001 hsize_t size[1] = {1};
01002 hid_t memspace = H5Screate_simple(1, size, NULL);
01003
01004
01005 hsize_t count[1] = {1};
01006 hsize_t offset[1] = {mCurrentTimeStep};
01007 hid_t hyperslab_space = H5Dget_space(mUnlimitedDatasetId);
01008 H5Sselect_hyperslab(hyperslab_space, H5S_SELECT_SET, offset, NULL, count, NULL);
01009
01010 H5Dwrite(mUnlimitedDatasetId, H5T_NATIVE_DOUBLE, memspace, hyperslab_space, H5P_DEFAULT, &value);
01011
01012 H5Sclose(hyperslab_space);
01013 H5Sclose(memspace);
01014 }
01015
01016 void Hdf5DataWriter::Close()
01017 {
01018 if (mIsInDefineMode)
01019 {
01020 return;
01021 }
01022
01023 H5Dclose(mVariablesDatasetId);
01024 if (mIsUnlimitedDimensionSet)
01025 {
01026 H5Dclose(mUnlimitedDatasetId);
01027 }
01028 H5Fclose(mFileId);
01029
01030
01031 mIsInDefineMode = true;
01032 }
01033
01034 void Hdf5DataWriter::DefineUnlimitedDimension(const std::string& rVariableName,
01035 const std::string& rVariableUnits,
01036 unsigned estimatedLength)
01037 {
01038 if (mIsUnlimitedDimensionSet)
01039 {
01040 EXCEPTION("Unlimited dimension already set. Cannot be defined twice");
01041 }
01042
01043 if (!mIsInDefineMode)
01044 {
01045 EXCEPTION("Cannot define variables when not in Define mode");
01046 }
01047
01048 this->mIsUnlimitedDimensionSet = true;
01049 this->mUnlimitedDimensionName = rVariableName;
01050 this->mUnlimitedDimensionUnit = rVariableUnits;
01051 mEstimatedUnlimitedLength = estimatedLength;
01052 }
01053
01054 void Hdf5DataWriter::AdvanceAlongUnlimitedDimension()
01055 {
01056 if (!mIsUnlimitedDimensionSet)
01057 {
01058 EXCEPTION("Trying to advance along an unlimited dimension without having defined any");
01059 }
01060
01061 mCurrentTimeStep++;
01062
01063
01064
01065
01066
01067 if ( mCurrentTimeStep >= (long unsigned) mEstimatedUnlimitedLength )
01068 {
01069 mDatasetDims[0]++;
01070 mNeedExtend = true;
01071 }
01072 }
01073
01074 void Hdf5DataWriter::PossiblyExtend()
01075 {
01076 if (mNeedExtend)
01077 {
01078 #if H5_VERS_MAJOR>=1 && H5_VERS_MINOR>=8 // HDF5 1.8+
01079 H5Dset_extent( mVariablesDatasetId, mDatasetDims );
01080 H5Dset_extent( mUnlimitedDatasetId, &mDatasetDims[0] );
01081 #else // Deprecated
01082 H5Dextend( mVariablesDatasetId, mDatasetDims );
01083 H5Dextend( mUnlimitedDatasetId, mDatasetDims );
01084 #endif
01085 }
01086 mNeedExtend = false;
01087 }
01088
01089 int Hdf5DataWriter::GetVariableByName(const std::string& rVariableName)
01090 {
01091 int id = -1;
01092
01093
01094 for (unsigned index=0; index<mVariables.size(); index++)
01095 {
01096 if (mVariables[index].mVariableName == rVariableName)
01097 {
01098 id = index;
01099 break;
01100 }
01101 }
01102 if (id == -1)
01103 {
01104 EXCEPTION("Variable does not exist in hdf5 definitions.");
01105 }
01106 return id;
01107 }
01108
01109 bool Hdf5DataWriter::ApplyPermutation(const std::vector<unsigned>& rPermutation, bool unsafeExtendingMode)
01110 {
01111 if (unsafeExtendingMode == false && !mIsInDefineMode)
01112 {
01113 EXCEPTION("Cannot define permutation when not in Define mode");
01114 }
01115
01116 if (rPermutation.empty())
01117 {
01118 return false;
01119 }
01120
01121 if (rPermutation.size() != mFileFixedDimensionSize ||
01122 rPermutation.size() != mDataFixedDimensionSize)
01123 {
01124 EXCEPTION("Permutation doesn't match the expected problem size");
01125 }
01126
01127
01128 std::set<unsigned> permutation_pigeon_hole;
01129
01130
01131 bool identity_map = true;
01132 for (unsigned i=0; i<mDataFixedDimensionSize; i++)
01133 {
01134 permutation_pigeon_hole.insert(rPermutation[i]);
01135 if (identity_map && i != rPermutation[i])
01136 {
01137 identity_map = false;
01138 }
01139 }
01140 if (identity_map)
01141 {
01142
01143 return false;
01144 }
01145
01146
01147
01148
01149
01150
01151 for (unsigned i=0; i<mDataFixedDimensionSize; i++)
01152 {
01153 if (permutation_pigeon_hole.count(i) != 1u)
01154 {
01155 EXCEPTION("Permutation vector doesn't contain a valid permutation");
01156 }
01157 }
01158
01159 assert(mSinglePermutation == NULL);
01160 assert(mDoublePermutation == NULL);
01161 PetscTools::SetupMat(mSinglePermutation, mDataFixedDimensionSize, mDataFixedDimensionSize, 2, mHi - mLo, mHi - mLo);
01162 PetscTools::SetupMat(mDoublePermutation, 2*mDataFixedDimensionSize, 2*mDataFixedDimensionSize, 4, 2*(mHi - mLo), 2*(mHi - mLo));
01163 #if (PETSC_VERSION_MAJOR == 3) //PETSc 3.x.x
01164 MatSetOption(mSinglePermutation, MAT_IGNORE_OFF_PROC_ENTRIES, PETSC_TRUE);
01165 MatSetOption(mDoublePermutation, MAT_IGNORE_OFF_PROC_ENTRIES, PETSC_TRUE);
01166 #else
01167 MatSetOption(mSinglePermutation, MAT_IGNORE_OFF_PROC_ENTRIES);
01168 MatSetOption(mDoublePermutation, MAT_IGNORE_OFF_PROC_ENTRIES);
01169 #endif
01170
01171 for (unsigned row_index=mLo; row_index<mHi; row_index++)
01172 {
01173
01174 MatSetValue(mSinglePermutation, row_index, row_index, 0.0, INSERT_VALUES);
01175
01176
01177 MatSetValue(mSinglePermutation, row_index, rPermutation[row_index], 1.0, INSERT_VALUES);
01178
01179 unsigned bi_index = 2*row_index;
01180 unsigned perm_index = 2*rPermutation[row_index];
01181
01182
01183 MatSetValue(mDoublePermutation, bi_index, bi_index, 0.0, INSERT_VALUES);
01184 MatSetValue(mDoublePermutation, bi_index+1, bi_index+1, 0.0, INSERT_VALUES);
01185
01186
01187 MatSetValue(mDoublePermutation, bi_index, perm_index, 1.0, INSERT_VALUES);
01188 MatSetValue(mDoublePermutation, bi_index+1, perm_index+1, 1.0, INSERT_VALUES);
01189 }
01190 MatAssemblyBegin(mSinglePermutation, MAT_FINAL_ASSEMBLY);
01191 MatAssemblyBegin(mDoublePermutation, MAT_FINAL_ASSEMBLY);
01192 MatAssemblyEnd(mSinglePermutation, MAT_FINAL_ASSEMBLY);
01193 MatAssemblyEnd(mDoublePermutation, MAT_FINAL_ASSEMBLY);
01194 return true;
01195 }
01196
01197 void Hdf5DataWriter::SetFixedChunkSize(const unsigned& rTimestepsPerChunk,
01198 const unsigned& rNodesPerChunk,
01199 const unsigned& rVariablesPerChunk)
01200 {
01201 assert(mIsInDefineMode);
01202
01203 mUseOptimalChunkSizeAlgorithm = false;
01204 mFixedChunkSize[0] = rTimestepsPerChunk;
01205 mFixedChunkSize[1] = rNodesPerChunk;
01206 mFixedChunkSize[2] = rVariablesPerChunk;
01207 }
01208
01209 hsize_t Hdf5DataWriter::CalculateNumberOfChunks()
01210 {
01211
01212 hsize_t num_chunks = 1;
01213 for (unsigned i=0; i<DATASET_DIMS; ++i)
01214 {
01215 num_chunks *= CeilDivide(mDatasetDims[i], mChunkSize[i]);
01216 }
01217 return num_chunks;
01218 }
01219
01220 void Hdf5DataWriter::CalculateChunkDims( unsigned targetSize, unsigned* pChunkSizeInBytes, bool* pAllOneChunk )
01221 {
01222 bool all_one_chunk = true;
01223 unsigned chunk_size_in_bytes = 8u;
01224 unsigned divisors[DATASET_DIMS];
01225
01226
01227
01228 for (unsigned i=0; i<DATASET_DIMS; ++i)
01229 {
01230
01231 divisors[i] = CeilDivide(mDatasetDims[i], targetSize);
01232
01233 mChunkSize[i] = CeilDivide(mDatasetDims[i], divisors[i]);
01234
01235 chunk_size_in_bytes *= mChunkSize[i];
01236
01237 all_one_chunk = all_one_chunk && divisors[i]==1u;
01238 }
01239
01240 *pChunkSizeInBytes = chunk_size_in_bytes;
01241 *pAllOneChunk = all_one_chunk;
01242 }
01243
01244 void Hdf5DataWriter::SetChunkSize()
01245 {
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255 const unsigned recommended_max_number_chunks = 75000;
01256 if (mUseOptimalChunkSizeAlgorithm)
01257 {
01258
01259
01260
01261
01262
01263
01264
01265
01266
01267
01268 unsigned target_size_in_bytes = 1024*1024/8;
01269
01270 unsigned target_size = 0;
01271 unsigned chunk_size_in_bytes;
01272 bool all_one_chunk;
01273
01274
01275 do
01276 {
01277
01278
01279 do
01280 {
01281 target_size++;
01282 CalculateChunkDims(target_size, &chunk_size_in_bytes, &all_one_chunk);
01283 }
01284 while ( chunk_size_in_bytes < target_size_in_bytes && !all_one_chunk);
01285
01286
01287 if ( chunk_size_in_bytes > target_size_in_bytes && !all_one_chunk )
01288 {
01289 target_size--;
01290 CalculateChunkDims(target_size, &chunk_size_in_bytes, &all_one_chunk);
01291 }
01292
01293 mNumberOfChunks = CalculateNumberOfChunks();
01294
01295
01296
01297
01298
01299
01300
01301
01302 target_size_in_bytes *= 2;
01303 }
01304 while ( mNumberOfChunks > recommended_max_number_chunks );
01305 }
01306
01307
01308
01309
01310 else
01311 {
01312 for (unsigned i=0; i<DATASET_DIMS; ++i)
01313 {
01314 mChunkSize[i] = mFixedChunkSize[i];
01315 }
01316
01317 mNumberOfChunks = CalculateNumberOfChunks();
01318
01319 if ( mNumberOfChunks > recommended_max_number_chunks)
01320 {
01321
01322
01323
01324
01325
01326 NEVER_REACHED;
01327 }
01328 }
01329 }