Field3D
SparseFieldIO.cpp
Go to the documentation of this file.
1 //----------------------------------------------------------------------------//
2 
3 /*
4  * Copyright (c) 2009 Sony Pictures Imageworks Inc
5  *
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * Redistributions in binary form must reproduce the above copyright
15  * notice, this list of conditions and the following disclaimer in the
16  * documentation and/or other materials provided with the
17  * distribution. Neither the name of Sony Pictures Imageworks nor the
18  * names of its contributors may be used to endorse or promote
19  * products derived from this software without specific prior written
20  * permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
33  * OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 //----------------------------------------------------------------------------//
37 
42 //----------------------------------------------------------------------------//
43 
44 #include <boost/intrusive_ptr.hpp>
45 
46 #include <boost/thread/thread.hpp>
47 #include <boost/thread/mutex.hpp>
48 
49 #include "InitIO.h"
50 #include "SparseFieldIO.h"
51 #include "Types.h"
52 
53 //----------------------------------------------------------------------------//
54 
55 using namespace boost;
56 using namespace std;
57 
58 //----------------------------------------------------------------------------//
59 
61 
62 //----------------------------------------------------------------------------//
63 // Field3D namespaces
64 //----------------------------------------------------------------------------//
65 
66 using namespace Exc;
67 using namespace Hdf5Util;
68 
69 //----------------------------------------------------------------------------//
70 // Anonymous namespace
71 //----------------------------------------------------------------------------//
72 
73 namespace {
74 
75 //----------------------------------------------------------------------------//
76 
77 template <typename Data_T>
78 struct ReadThreadingState
79 {
80  ReadThreadingState(const OgIGroup &i_location,
81  Sparse::SparseBlock<Data_T> *i_blocks,
82  const size_t i_numVoxels,
83  const size_t i_numBlocks,
84  const size_t i_numOccupiedBlocks,
85  const bool i_isCompressed,
86  const std::vector<size_t> &i_blockIdxToDatasetIdx)
87  : location(i_location),
88  blocks(i_blocks),
89  numVoxels(i_numVoxels),
90  numBlocks(i_numBlocks),
91  numOccupiedBlocks(i_numOccupiedBlocks),
92  isCompressed(i_isCompressed),
93  blockIdxToDatasetIdx(i_blockIdxToDatasetIdx),
94  nextBlockToRead(0)
95  { }
96  // Data members
97  const OgIGroup &location;
99  const size_t numVoxels;
100  const size_t numBlocks;
101  const size_t numOccupiedBlocks;
102  const bool isCompressed;
103  const std::vector<size_t> &blockIdxToDatasetIdx;
104  size_t nextBlockToRead;
105  // Mutexes
106  boost::mutex readMutex;
107 };
108 
109 //----------------------------------------------------------------------------//
110 
111 template <typename Data_T>
112 class ReadBlockOp
113 {
114 public:
115  ReadBlockOp(ReadThreadingState<Data_T> &state, const size_t threadId)
116  : m_state(state)
117  {
118  // Set up the compression cache
119  const uLong srcLen = m_state.numVoxels * sizeof(Data_T);
120  const uLong cmpLenBound = compressBound(srcLen);
121  m_cache.resize(cmpLenBound);
122  // Initialize the reader
123  m_readerPtr.reset(
124  new OgSparseDataReader<Data_T>(m_state.location, m_state.numVoxels,
125  m_state.numOccupiedBlocks,
126  m_state.isCompressed));
127  m_reader = m_readerPtr.get();
128  // Set the thread id
129  m_reader->setThreadId(threadId);
130  }
131  void operator() ()
132  {
133  // Get next block to read
134  size_t blockIdx;
135  {
136  boost::mutex::scoped_lock lock(m_state.readMutex);
137  blockIdx = m_state.nextBlockToRead;
138  m_state.nextBlockToRead++;
139  }
140  // Loop over blocks until we run out
141  while (blockIdx < m_state.numBlocks) {
142  if (m_state.blocks[blockIdx].isAllocated) {
143  const size_t datasetIdx = m_state.blockIdxToDatasetIdx[blockIdx];
144  m_reader->readBlock(datasetIdx, m_state.blocks[blockIdx].data);
145  }
146  // Get next block idx
147  {
148  boost::mutex::scoped_lock lock(m_state.readMutex);
149  blockIdx = m_state.nextBlockToRead;
150  m_state.nextBlockToRead++;
151  }
152  }
153  }
154 private:
155  // Data members ---
156  ReadThreadingState<Data_T> &m_state;
157  std::vector<uint8_t> m_cache;
158  boost::shared_ptr<OgSparseDataReader<Data_T> > m_readerPtr;
159  OgSparseDataReader<Data_T> *m_reader;
160 };
161 
162 //----------------------------------------------------------------------------//
163 
164 template <typename Data_T>
165 struct ThreadingState
166 {
167  ThreadingState(OgOCDataset<Data_T> &i_data,
168  Sparse::SparseBlock<Data_T> *i_blocks,
169  const size_t i_numVoxels,
170  const size_t i_numBlocks,
171  const std::vector<uint8_t> &i_isAllocated)
172  : data(i_data),
173  blocks(i_blocks),
174  numVoxels(i_numVoxels),
175  numBlocks(i_numBlocks),
176  isAllocated(i_isAllocated),
177  nextBlockToCompress(0),
178  nextBlockToWrite(0)
179  {
180  // Find first in-use block
181  for (size_t i = 0; i < numBlocks; ++i) {
182  if (blocks[i].isAllocated) {
183  nextBlockToCompress = i;
184  nextBlockToWrite = i;
185  return;
186  }
187  }
188  // If we get here, there are no active blocks. Set to numBlocks
189  nextBlockToCompress = numBlocks;
190  nextBlockToWrite = numBlocks;
191  }
192  // Data members
193  OgOCDataset<Data_T> &data;
195  const size_t numVoxels;
196  const size_t numBlocks;
197  const std::vector<uint8_t> isAllocated;
198  size_t nextBlockToCompress;
199  size_t nextBlockToWrite;
200  // Mutexes
201  boost::mutex compressMutex;
202 };
203 
204 //----------------------------------------------------------------------------//
205 
206 template <typename Data_T>
207 class WriteBlockOp
208 {
209 public:
210  WriteBlockOp(ThreadingState<Data_T> &state, const size_t threadId)
211  : m_state(state), m_threadId(threadId)
212  {
213  const uLong srcLen = m_state.numVoxels * sizeof(Data_T);
214  const uLong cmpLenBound = compressBound(srcLen);
215  m_cache.resize(cmpLenBound);
216  }
217  void operator() ()
218  {
219  const int level = 1;
220  // Get next block to compress
221  size_t blockIdx;
222  {
223  boost::mutex::scoped_lock lock(m_state.compressMutex);
224  blockIdx = m_state.nextBlockToCompress;
225  // Step counter to next
226  while (m_state.nextBlockToCompress < m_state.numBlocks) {
227  m_state.nextBlockToCompress++;
228  if (m_state.blocks[m_state.nextBlockToCompress].isAllocated) {
229  break;
230  }
231  }
232  }
233  // Loop over blocks until we run out
234  while (blockIdx < m_state.numBlocks) {
235  if (m_state.blocks[blockIdx].isAllocated) {
236  // Block data as bytes
237  const uint8_t *srcData =
238  reinterpret_cast<const uint8_t *>(m_state.blocks[blockIdx].data);
239  // Length of compressed data is stored here
240  const uLong srcLen = m_state.numVoxels * sizeof(Data_T);
241  const uLong cmpLenBound = compressBound(srcLen);
242  uLong cmpLen = cmpLenBound;
243  // Perform compression
244  const int status = compress2(&m_cache[0], &cmpLen,
245  srcData, srcLen, level);
246  // Error check
247  if (status != Z_OK) {
248  std::cout << "ERROR: Couldn't compress in SparseFieldIO." << std::endl
249  << " Level: " << level << std::endl
250  << " Status: " << status << std::endl
251  << " srcLen: " << srcLen << std::endl
252  << " cmpLenBound: " << cmpLenBound << std::endl
253  << " cmpLen: " << cmpLen << std::endl;
254  return;
255  }
256  // Wait to write data
257  while (m_state.nextBlockToWrite != blockIdx) {
258  // Spin
259  boost::this_thread::sleep(boost::posix_time::microseconds(1));
260  }
261  // Do the writing
262  m_state.data.addData(cmpLen, &m_cache[0]);
263  // Let next block write
264  while (m_state.nextBlockToWrite < m_state.numBlocks){
265  // Increment to next
266  m_state.nextBlockToWrite++;
267  if (m_state.blocks[m_state.nextBlockToWrite].isAllocated) {
268  break;
269  }
270  }
271  }
272  // Get next block idx
273  {
274  boost::mutex::scoped_lock lock(m_state.compressMutex);
275  blockIdx = m_state.nextBlockToCompress;
276  // Step counter to next
277  while (m_state.nextBlockToCompress < m_state.numBlocks) {
278  m_state.nextBlockToCompress++;
279  if (m_state.blocks[m_state.nextBlockToCompress].isAllocated) {
280  break;
281  }
282  }
283  }
284  }
285  }
286 private:
287  // Data members ---
288  ThreadingState<Data_T> &m_state;
289  std::vector<uint8_t> m_cache;
290  const size_t m_threadId;
291 };
292 
293 //----------------------------------------------------------------------------//
294 
295 } // Anonymous namespace
296 
297 //----------------------------------------------------------------------------//
298 // Static members
299 //----------------------------------------------------------------------------//
300 
301 const int SparseFieldIO::k_versionNumber(1);
302 const std::string SparseFieldIO::k_versionAttrName("version");
303 const std::string SparseFieldIO::k_extentsStr("extents");
304 const std::string SparseFieldIO::k_extentsMinStr("extents_min");
305 const std::string SparseFieldIO::k_extentsMaxStr("extents_max");
306 const std::string SparseFieldIO::k_dataWindowStr("data_window");
307 const std::string SparseFieldIO::k_dataWindowMinStr("data_window_min");
308 const std::string SparseFieldIO::k_dataWindowMaxStr("data_window_max");
309 const std::string SparseFieldIO::k_componentsStr("components");
310 const std::string SparseFieldIO::k_dataStr("data");
311 const std::string SparseFieldIO::k_blockOrderStr("block_order");
312 const std::string SparseFieldIO::k_numBlocksStr("num_blocks");
313 const std::string SparseFieldIO::k_blockResStr("block_res");
314 const std::string SparseFieldIO::k_bitsPerComponentStr("bits_per_component");
315 const std::string SparseFieldIO::k_numOccupiedBlocksStr("num_occupied_blocks");
316 const std::string SparseFieldIO::k_isCompressed("data_is_compressed");
317 
318 //----------------------------------------------------------------------------//
319 
321 SparseFieldIO::read(hid_t layerGroup, const std::string &filename,
322  const std::string &layerPath,
323  DataTypeEnum typeEnum)
324 {
325  Box3i extents, dataW;
326  int components;
327  int blockOrder;
328  int numBlocks;
329  V3i blockRes;
330 
331  if (layerGroup == -1) {
332  Msg::print(Msg::SevWarning, "Bad layerGroup.");
333  return FieldBase::Ptr();
334  }
335 
336  int version;
337  if (!readAttribute(layerGroup, k_versionAttrName, 1, version))
338  throw MissingAttributeException("Couldn't find attribute: " +
339  k_versionAttrName);
340 
341  if (version != k_versionNumber)
342  throw UnsupportedVersionException("SparseField version not supported: " +
343  lexical_cast<std::string>(version));
344 
345  if (!readAttribute(layerGroup, k_extentsStr, 6, extents.min.x))
346  throw MissingAttributeException("Couldn't find attribute: " +
347  k_extentsStr);
348 
349  if (!readAttribute(layerGroup, k_dataWindowStr, 6, dataW.min.x))
350  throw MissingAttributeException("Couldn't find attribute: " +
351  k_dataWindowStr);
352 
353  if (!readAttribute(layerGroup, k_componentsStr, 1, components))
354  throw MissingAttributeException("Couldn't find attribute: " +
355  k_componentsStr);
356 
357  // Read block order
358  if (!readAttribute(layerGroup, k_blockOrderStr, 1, blockOrder))
359  throw MissingAttributeException("Couldn't find attribute: " +
360  k_blockOrderStr);
361 
362  // Read number of blocks total
363  if (!readAttribute(layerGroup, k_numBlocksStr, 1, numBlocks))
364  throw MissingAttributeException("Couldn't find attribute: " +
365  k_numBlocksStr);
366 
367  // Read block resolution in each dimension
368  if (!readAttribute(layerGroup, k_blockResStr, 3, blockRes.x))
369  throw MissingAttributeException("Couldn't find attribute: " +
370  k_blockResStr);
371 
372  // ... Check that it matches the # reported by summing the active blocks
373 
374  int numCalculatedBlocks = blockRes.x * blockRes.y * blockRes.z;
375  if (numCalculatedBlocks != numBlocks)
376  throw FileIntegrityException("Incorrect block count in SparseFieldIO::read");
377 
378  // Call the appropriate read function based on the data type ---
379 
380  FieldBase::Ptr result;
381 
382  int occupiedBlocks;
383  if (!readAttribute(layerGroup, k_numOccupiedBlocksStr, 1, occupiedBlocks))
384  throw MissingAttributeException("Couldn't find attribute: " +
385  k_numOccupiedBlocksStr);
386 
387  // Check the data type ---
388 
389  int bits;
390  if (!readAttribute(layerGroup, k_bitsPerComponentStr, 1, bits))
391  throw MissingAttributeException("Couldn't find attribute: " +
392  k_bitsPerComponentStr);
393 
394  bool isHalf = false;
395  bool isFloat = false;
396  bool isDouble = false;
397 
398  switch (bits) {
399  case 16:
400  isHalf = true;
401  break;
402  case 64:
403  isDouble = true;
404  break;
405  case 32:
406  default:
407  isFloat = true;
408  }
409 
410  // Finally, read the data ---
411 
412  if (components == 1) {
413  if (isHalf && typeEnum == DataTypeHalf) {
415  field->setSize(extents, dataW);
416  field->setBlockOrder(blockOrder);
417  readData<half>(layerGroup, numBlocks, filename, layerPath, field);
418  result = field;
419  } else if (isFloat && typeEnum == DataTypeFloat) {
421  field->setSize(extents, dataW);
422  field->setBlockOrder(blockOrder);
423  readData<float>(layerGroup, numBlocks, filename, layerPath, field);
424  result = field;
425  } else if (isDouble && typeEnum == DataTypeDouble) {
427  field->setSize(extents, dataW);
428  field->setBlockOrder(blockOrder);
429  readData<double>(layerGroup, numBlocks, filename, layerPath, field);
430  result = field;
431  }
432  } else if (components == 3) {
433  if (isHalf && typeEnum == DataTypeVecHalf) {
435  field->setSize(extents, dataW);
436  field->setBlockOrder(blockOrder);
437  readData<V3h>(layerGroup, numBlocks, filename, layerPath, field);
438  result = field;
439  } else if (isFloat && typeEnum == DataTypeVecFloat) {
441  field->setSize(extents, dataW);
442  field->setBlockOrder(blockOrder);
443  readData<V3f>(layerGroup, numBlocks, filename, layerPath, field);
444  result = field;
445  } else if (isDouble && typeEnum == DataTypeVecDouble) {
447  field->setSize(extents, dataW);
448  field->setBlockOrder(blockOrder);
449  readData<V3d>(layerGroup, numBlocks, filename, layerPath, field);
450  result = field;
451  }
452  }
453 
454  return result;
455 }
456 
457 //----------------------------------------------------------------------------//
458 
460 SparseFieldIO::read(const OgIGroup &layerGroup, const std::string &filename,
461  const std::string &layerPath, OgDataType typeEnum)
462 {
463  Box3i extents, dataW;
464  int blockOrder;
465  int numBlocks;
466  V3i blockRes;
467 
468  if (!layerGroup.isValid()) {
469  throw MissingGroupException("Invalid group in SparseFieldIO::read()");
470  }
471 
472  // Check version ---
473 
474  OgIAttribute<int> versionAttr =
475  layerGroup.findAttribute<int>(k_versionAttrName);
476  if (!versionAttr.isValid()) {
477  throw MissingAttributeException("Couldn't find attribute: " +
478  k_versionAttrName);
479  }
480  const int version = versionAttr.value();
481 
482  if (version != k_versionNumber) {
483  throw UnsupportedVersionException("SparseField version not supported: " +
484  lexical_cast<std::string>(version));
485  }
486 
487  // Get extents ---
488 
489  OgIAttribute<veci32_t> extMinAttr =
490  layerGroup.findAttribute<veci32_t>(k_extentsMinStr);
491  OgIAttribute<veci32_t> extMaxAttr =
492  layerGroup.findAttribute<veci32_t>(k_extentsMaxStr);
493  if (!extMinAttr.isValid()) {
494  throw MissingAttributeException("Couldn't find attribute " +
495  k_extentsMinStr);
496  }
497  if (!extMaxAttr.isValid()) {
498  throw MissingAttributeException("Couldn't find attribute " +
499  k_extentsMaxStr);
500  }
501 
502  extents.min = extMinAttr.value();
503  extents.max = extMaxAttr.value();
504 
505  // Get data window ---
506 
507  OgIAttribute<veci32_t> dwMinAttr =
508  layerGroup.findAttribute<veci32_t>(k_dataWindowMinStr);
509  OgIAttribute<veci32_t> dwMaxAttr =
510  layerGroup.findAttribute<veci32_t>(k_dataWindowMaxStr);
511  if (!dwMinAttr.isValid()) {
512  throw MissingAttributeException("Couldn't find attribute " +
513  k_dataWindowMinStr);
514  }
515  if (!dwMaxAttr.isValid()) {
516  throw MissingAttributeException("Couldn't find attribute " +
517  k_dataWindowMaxStr);
518  }
519 
520  dataW.min = dwMinAttr.value();
521  dataW.max = dwMaxAttr.value();
522 
523  // Get num components ---
524 
525  OgIAttribute<uint8_t> numComponentsAttr =
526  layerGroup.findAttribute<uint8_t>(k_componentsStr);
527  if (!numComponentsAttr.isValid()) {
528  throw MissingAttributeException("Couldn't find attribute " +
529  k_componentsStr);
530  }
531 
532  // Read block order ---
533 
534  OgIAttribute<uint8_t> blockOrderAttr =
535  layerGroup.findAttribute<uint8_t>(k_blockOrderStr);
536  if (!blockOrderAttr.isValid()) {
537  throw MissingAttributeException("Couldn't find attribute: " +
538  k_blockOrderStr);
539  }
540  blockOrder = blockOrderAttr.value();
541 
542  // Read number of blocks total ---
543 
544  OgIAttribute<uint32_t> numBlocksAttr =
545  layerGroup.findAttribute<uint32_t>(k_numBlocksStr);
546  if (!numBlocksAttr.isValid()) {
547  throw MissingAttributeException("Couldn't find attribute: " +
548  k_numBlocksStr);
549  }
550  numBlocks = numBlocksAttr.value();
551 
552  // Read block resolution in each dimension ---
553 
554  OgIAttribute<veci32_t> blockResAttr =
555  layerGroup.findAttribute<veci32_t>(k_blockResStr);
556  if (!blockResAttr.isValid()) {
557  throw MissingAttributeException("Couldn't find attribute: " +
558  k_blockResStr);
559  }
560  blockRes = blockResAttr.value();
561 
562  // ... Check that it matches the # reported by summing the active blocks
563 
564  int numCalculatedBlocks = blockRes.x * blockRes.y * blockRes.z;
565  if (numCalculatedBlocks != numBlocks) {
566  throw FileIntegrityException("Incorrect block count in "
567  "SparseFieldIO::read()");
568  }
569 
570  // Call the appropriate read function based on the data type ---
571 
572  OgIAttribute<uint32_t> occupiedBlocksAttr =
573  layerGroup.findAttribute<uint32_t>(k_numOccupiedBlocksStr);
574  if (!occupiedBlocksAttr.isValid()) {
575  throw MissingAttributeException("Couldn't find attribute: " +
576  k_numOccupiedBlocksStr);
577  }
578 
579  // Check if the data is compressed ---
580 
581  OgIAttribute<uint8_t> isCompressedAttr =
582  layerGroup.findAttribute<uint8_t>(k_isCompressed);
583  if (!isCompressedAttr.isValid()) {
584  throw MissingAttributeException("Couldn't find attribute: " +
585  k_isCompressed);
586  }
587 
588  // Finally, read the data ---
589 
590  FieldBase::Ptr result;
591 
592  OgDataType typeOnDisk;
593 
594  if (isCompressedAttr.value() == 0) {
595  typeOnDisk = layerGroup.datasetType(k_dataStr);
596  } else {
597  typeOnDisk = layerGroup.compressedDatasetType(k_dataStr);
598  }
599 
600  if (typeEnum == typeOnDisk) {
601  if (typeEnum == F3DFloat16) {
602  result = readData<float16_t>(layerGroup, extents, dataW, blockOrder,
603  numBlocks, filename, layerPath);
604  } else if (typeEnum == F3DFloat32) {
605  result = readData<float32_t>(layerGroup, extents, dataW, blockOrder,
606  numBlocks, filename, layerPath);
607  } else if (typeEnum == F3DFloat64) {
608  result = readData<float64_t>(layerGroup, extents, dataW, blockOrder,
609  numBlocks, filename, layerPath);
610  } else if (typeEnum == F3DVec16) {
611  result = readData<vec16_t>(layerGroup, extents, dataW, blockOrder,
612  numBlocks, filename, layerPath);
613  } else if (typeEnum == F3DVec32) {
614  result = readData<vec32_t>(layerGroup, extents, dataW, blockOrder,
615  numBlocks, filename, layerPath);
616  } else if (typeEnum == F3DVec64) {
617  result = readData<vec64_t>(layerGroup, extents, dataW, blockOrder,
618  numBlocks, filename, layerPath);
619  }
620  }
621 
622  return result;
623 }
624 
625 //----------------------------------------------------------------------------//
626 
627 bool
628 SparseFieldIO::write(hid_t layerGroup, FieldBase::Ptr field)
629 {
630  if (layerGroup == -1) {
631  Msg::print(Msg::SevWarning, "Bad layerGroup.");
632  return false;
633  }
634 
635  // Add version attribute
636  if (!writeAttribute(layerGroup, k_versionAttrName,
637  1, k_versionNumber)) {
638  Msg::print(Msg::SevWarning, "Error adding version attribute.");
639  return false;
640  }
641 
642  SparseField<half>::Ptr halfField =
644  SparseField<float>::Ptr floatField =
646  SparseField<double>::Ptr doubleField =
648  SparseField<V3h>::Ptr vecHalfField =
650  SparseField<V3f>::Ptr vecFloatField =
652  SparseField<V3d>::Ptr vecDoubleField =
654 
655  bool success = true;
656  if (halfField) {
657  success = writeInternal<half>(layerGroup, halfField);
658  } else if (floatField) {
659  success = writeInternal<float>(layerGroup, floatField);
660  } else if (doubleField) {
661  success = writeInternal<double>(layerGroup, doubleField);
662  } else if (vecHalfField) {
663  success = writeInternal<V3h>(layerGroup, vecHalfField);
664  } else if (vecFloatField) {
665  success = writeInternal<V3f>(layerGroup, vecFloatField);
666  } else if (vecDoubleField) {
667  success = writeInternal<V3d>(layerGroup, vecDoubleField);
668  } else {
669  throw WriteLayerException("SparseFieldIO::write does not support the given "
670  "SparseField template parameter");
671  }
672 
673  return success;
674 }
675 
676 //----------------------------------------------------------------------------//
677 
678 bool
679 SparseFieldIO::write(OgOGroup &layerGroup, FieldBase::Ptr field)
680 {
681  using namespace Exc;
682 
683  // Add version attribute
684  OgOAttribute<int> version(layerGroup, k_versionAttrName, k_versionNumber);
685 
686  SparseField<half>::Ptr halfField =
688  SparseField<float>::Ptr floatField =
690  SparseField<double>::Ptr doubleField =
692  SparseField<V3h>::Ptr vecHalfField =
694  SparseField<V3f>::Ptr vecFloatField =
696  SparseField<V3d>::Ptr vecDoubleField =
698 
699  bool success = true;
700 
701  if (floatField) {
702  success = writeInternal<float>(layerGroup, floatField);
703  }
704  else if (halfField) {
705  success = writeInternal<half>(layerGroup, halfField);
706  }
707  else if (doubleField) {
708  success = writeInternal<double>(layerGroup, doubleField);
709  }
710  else if (vecFloatField) {
711  success = writeInternal<V3f>(layerGroup, vecFloatField);
712  }
713  else if (vecHalfField) {
714  success = writeInternal<V3h>(layerGroup, vecHalfField);
715  }
716  else if (vecDoubleField) {
717  success = writeInternal<V3d>(layerGroup, vecDoubleField);
718  }
719  else {
720  throw WriteLayerException("SparseFieldIO does not support the given "
721  "SparseField template parameter");
722  }
723 
724  return success;
725 }
726 
727 //----------------------------------------------------------------------------//
728 
729 template <class Data_T>
731 SparseFieldIO::readData(const OgIGroup &location, const Box3i &extents,
732  const Box3i &dataW, const size_t blockOrder,
733  const size_t numBlocks, const std::string &filename,
734  const std::string &layerPath)
735 {
736  using namespace std;
737  using namespace Exc;
738  using namespace Sparse;
739 
740  typename SparseField<Data_T>::Ptr result(new SparseField<Data_T>);
741  result->setSize(extents, dataW);
742  result->setBlockOrder(blockOrder);
743 
744  const bool dynamicLoading = SparseFileManager::singleton().doLimitMemUse();
745  const int components = FieldTraits<Data_T>::dataDims();
746  const size_t numVoxels = (1 << (result->m_blockOrder * 3));
747  const int valuesPerBlock = (1 << (result->m_blockOrder * 3)) * components;
748 
749  // Read the number of occupied blocks ---
750 
751  OgIAttribute<uint32_t> occupiedBlocksAttr =
752  location.findAttribute<uint32_t>(k_numOccupiedBlocksStr);
753  if (!occupiedBlocksAttr.isValid()) {
754  throw MissingAttributeException("Couldn't find attribute: " +
755  k_numOccupiedBlocksStr);
756  }
757  const size_t occupiedBlocks = occupiedBlocksAttr.value();
758 
759  // Set up the dynamic read info ---
760 
761  if (dynamicLoading) {
762  // Set up the field reference
764  result->addReference(filename, layerPath, valuesPerBlock, numVoxels,
765  occupiedBlocks);
766  }
767 
768  // Read the block info data sets ---
769 
770  SparseBlock<Data_T> *blocks = result->m_blocks;
771 
772  // ... Read the isAllocated array and set up the block mapping array
773  std::vector<size_t> blockIdxToDatasetIdx(numBlocks);
774 
775  {
776  // Grab the data
777  vector<uint8_t> isAllocated(numBlocks);
778  OgIDataset<uint8_t> isAllocatedData =
779  location.findDataset<uint8_t>("block_is_allocated_data");
780  if (!isAllocatedData.isValid()) {
781  throw MissingGroupException("Couldn't find block_is_allocated_data: ");
782  }
783  isAllocatedData.getData(0, &isAllocated[0], OGAWA_THREAD);
784  // Allocate the blocks and set up the block mapping array
785  for (size_t i = 0, nextBlockOnDisk = 0; i < numBlocks; ++i) {
786  blocks[i].isAllocated = isAllocated[i];
787  if (!dynamicLoading && isAllocated[i]) {
788  blocks[i].resize(numVoxels);
789  // Update the block mapping array
790  blockIdxToDatasetIdx[i] = nextBlockOnDisk;
791  nextBlockOnDisk++;
792  }
793  }
794  }
795 
796  // ... Read the emptyValue array ---
797 
798  {
799  // Grab the data
800  vector<Data_T> emptyValue(numBlocks);
801  OgIDataset<Data_T> emptyValueData =
802  location.findDataset<Data_T>("block_empty_value_data");
803  if (!emptyValueData.isValid()) {
804  throw MissingGroupException("Couldn't find block_empty_value_data: ");
805  }
806  emptyValueData.getData(0, &emptyValue[0], OGAWA_THREAD);
807  // Fill in the field
808  for (size_t i = 0; i < numBlocks; ++i) {
809  blocks[i].emptyValue = emptyValue[i];
810  }
811  }
812 
813  // Read the data ---
814 
815  // Check whether data is compressed
816  OgIAttribute<uint8_t> isCompressedAttr =
817  location.findAttribute<uint8_t>(k_isCompressed);
818  const bool isCompressed = isCompressedAttr.value() != 0;
819 
820  if (occupiedBlocks > 0) {
821  if (dynamicLoading) {
822  // Defer loading to the sparse cache
823  result->setupReferenceBlocks();
824  } else {
825  // Threading state
826  ReadThreadingState<Data_T> state(location, blocks, numVoxels, numBlocks,
827  occupiedBlocks, isCompressed,
828  blockIdxToDatasetIdx);
829  // Number of threads
830  const size_t numThreads = numIOThreads();
831  // Launch threads
832  boost::thread_group threads;
833  for (size_t i = 0; i < numThreads; ++i) {
834  threads.create_thread(ReadBlockOp<Data_T>(state, i));
835  }
836  threads.join_all();
837  }
838  }
839 
840  return result;
841 }
842 
843 //----------------------------------------------------------------------------//
844 // Template implementations
845 //----------------------------------------------------------------------------//
846 
848 template <class Data_T>
849 bool SparseFieldIO::writeInternal(hid_t layerGroup,
850  typename SparseField<Data_T>::Ptr field)
851 {
852  using namespace std;
853  using namespace Exc;
854  using namespace Hdf5Util;
855  using namespace Sparse;
856 
857  Box3i ext(field->extents()), dw(field->dataWindow());
858 
859  int components = FieldTraits<Data_T>::dataDims();
860 
861  int valuesPerBlock = (1 << (field->m_blockOrder * 3)) * components;
862 
863  // Add extents attribute ---
864 
865  int extents[6] =
866  { ext.min.x, ext.min.y, ext.min.z, ext.max.x, ext.max.y, ext.max.z };
867 
868  if (!writeAttribute(layerGroup, k_extentsStr, 6, extents[0])) {
869  Msg::print(Msg::SevWarning, "Error adding size attribute.");
870  return false;
871  }
872 
873  // Add data window attribute ---
874 
875  int dataWindow[6] =
876  { dw.min.x, dw.min.y, dw.min.z, dw.max.x, dw.max.y, dw.max.z };
877 
878  if (!writeAttribute(layerGroup, k_dataWindowStr, 6, dataWindow[0])) {
879  Msg::print(Msg::SevWarning, "Error adding size attribute.");
880  return false;
881  }
882 
883  // Add components attribute ---
884 
885  if (!writeAttribute(layerGroup, k_componentsStr, 1, components)) {
886  Msg::print(Msg::SevWarning, "Error adding components attribute.");
887  return false;
888  }
889 
890  // Add block order attribute ---
891 
892  int blockOrder = field->m_blockOrder;
893 
894  if (!writeAttribute(layerGroup, k_blockOrderStr, 1, blockOrder)) {
895  Msg::print(Msg::SevWarning, "Error adding block order attribute.");
896  return false;
897  }
898 
899  // Add number of blocks attribute ---
900 
901  V3i &blockRes = field->m_blockRes;
902  int numBlocks = blockRes.x * blockRes.y * blockRes.z;
903 
904  if (!writeAttribute(layerGroup, k_numBlocksStr, 1, numBlocks)) {
905  Msg::print(Msg::SevWarning, "Error adding number of blocks attribute.");
906  return false;
907  }
908 
909  // Add block resolution in each dimension ---
910 
911  if (!writeAttribute(layerGroup, k_blockResStr, 3, blockRes.x)) {
912  Msg::print(Msg::SevWarning, "Error adding block res attribute.");
913  return false;
914  }
915 
916  // Add the bits per component attribute ---
917 
918  int bits = DataTypeTraits<Data_T>::h5bits();
919  if (!writeAttribute(layerGroup, k_bitsPerComponentStr, 1, bits)) {
920  Msg::print(Msg::SevWarning, "Error adding bits per component attribute.");
921  return false;
922  }
923 
924  // Write the block info data sets ---
925 
926  SparseBlock<Data_T> *blocks = field->m_blocks;
927 
928  // ... Write the isAllocated array
929  {
930  vector<char> isAllocated(numBlocks);
931  for (int i = 0; i < numBlocks; ++i) {
932  isAllocated[i] = static_cast<char>(blocks[i].isAllocated);
933  }
934  writeSimpleData<char>(layerGroup, "block_is_allocated_data", isAllocated);
935  }
936 
937  // ... Write the emptyValue array
938  {
939  vector<Data_T> emptyValue(numBlocks);
940  for (int i = 0; i < numBlocks; ++i) {
941  emptyValue[i] = static_cast<Data_T>(blocks[i].emptyValue);
942  }
943  writeSimpleData<Data_T>(layerGroup, "block_empty_value_data", emptyValue);
944  }
945 
946  // Count the number of occupied blocks ---
947  int occupiedBlocks = 0;
948  for (int i = 0; i < numBlocks; ++i) {
949  if (blocks[i].isAllocated) {
950  occupiedBlocks++;
951  }
952  }
953 
954  if (!writeAttribute(layerGroup, k_numOccupiedBlocksStr, 1, occupiedBlocks)) {
955  throw WriteAttributeException("Couldn't add attribute " +
956  k_numOccupiedBlocksStr);
957  }
958 
959  if (occupiedBlocks > 0) {
960 
961  // Make the memory data space
962  hsize_t memDims[1];
963  memDims[0] = valuesPerBlock;
964  H5ScopedScreate memDataSpace(H5S_SIMPLE);
965  H5Sset_extent_simple(memDataSpace.id(), 1, memDims, NULL);
966 
967  // Make the file data space
968  hsize_t fileDims[2];
969  fileDims[0] = occupiedBlocks;
970  fileDims[1] = valuesPerBlock;
971  H5ScopedScreate fileDataSpace(H5S_SIMPLE);
972  H5Sset_extent_simple(fileDataSpace.id(), 2, fileDims, NULL);
973 
974  // Set up gzip property list
975  bool gzipAvailable = checkHdf5Gzip();
976  hid_t dcpl = H5Pcreate(H5P_DATASET_CREATE);
977  hsize_t chunkSize[2];
978  chunkSize[0] = 1;
979  chunkSize[1] = valuesPerBlock;
980  if (gzipAvailable) {
981  herr_t status = H5Pset_deflate(dcpl, 9);
982  if (status < 0) {
983  return false;
984  }
985  status = H5Pset_chunk(dcpl, 2, chunkSize);
986  if (status < 0) {
987  return false;
988  }
989  }
990 
991  // Add the data set
992  H5ScopedDcreate dataSet(layerGroup, k_dataStr,
994  fileDataSpace.id(),
995  H5P_DEFAULT, dcpl, H5P_DEFAULT);
996  if (dataSet.id() < 0)
997  throw CreateDataSetException("Couldn't create data set in "
998  "SparseFieldIO::writeInternal");
999 
1000  // For each allocated block ---
1001 
1002  int nextBlockIdx = 0;
1003  hsize_t offset[2];
1004  hsize_t count[2];
1005  herr_t status;
1006 
1007  for (int i = 0; i < numBlocks; ++i) {
1008  if (blocks[i].isAllocated) {
1009  offset[0] = nextBlockIdx; // Index of next block
1010  offset[1] = 0; // Index of first data in block. Always 0
1011  count[0] = 1; // Number of columns to read. Always 1
1012  count[1] = valuesPerBlock; // Number of values in one column
1013  status = H5Sselect_hyperslab(fileDataSpace.id(), H5S_SELECT_SET,
1014  offset, NULL, count, NULL);
1015  if (status < 0) {
1016  throw WriteHyperSlabException(
1017  "Couldn't select slab " +
1018  boost::lexical_cast<std::string>(nextBlockIdx));
1019  }
1020  Data_T *data = field->m_blocks[i].data;
1021  status = H5Dwrite(dataSet.id(), DataTypeTraits<Data_T>::h5type(),
1022  memDataSpace.id(),
1023  fileDataSpace.id(), H5P_DEFAULT, data);
1024  if (status < 0) {
1025  throw WriteHyperSlabException(
1026  "Couldn't write slab " +
1027  boost::lexical_cast<std::string>(nextBlockIdx));
1028  }
1029  // Increment nextBlockIdx
1030  nextBlockIdx++;
1031  }
1032  }
1033 
1034  } // if occupiedBlocks > 0
1035 
1036  return true;
1037 
1038 }
1039 
1040 //----------------------------------------------------------------------------//
1041 
1042 template <class Data_T>
1043 bool SparseFieldIO::writeInternal(OgOGroup &layerGroup,
1044  typename SparseField<Data_T>::Ptr field)
1045 {
1046  using namespace Exc;
1047  using namespace Sparse;
1048 
1049  SparseBlock<Data_T> *blocks = field->m_blocks;
1050 
1051  const int components = FieldTraits<Data_T>::dataDims();
1052  const int bits = DataTypeTraits<Data_T>::h5bits();
1053  const V3i &blockRes = field->m_blockRes;
1054  const size_t numBlocks = blockRes.x * blockRes.y * blockRes.z;
1055  const size_t numVoxels = (1 << (field->m_blockOrder * 3));
1056 
1057  const Box3i ext(field->extents()), dw(field->dataWindow());
1058 
1059  // Add attributes ---
1060 
1061  OgOAttribute<veci32_t> extMinAttr(layerGroup, k_extentsMinStr, ext.min);
1062  OgOAttribute<veci32_t> extMaxAttr(layerGroup, k_extentsMaxStr, ext.max);
1063 
1064  OgOAttribute<veci32_t> dwMinAttr(layerGroup, k_dataWindowMinStr, dw.min);
1065  OgOAttribute<veci32_t> dwMaxAttr(layerGroup, k_dataWindowMaxStr, dw.max);
1066 
1067  OgOAttribute<uint8_t> componentsAttr(layerGroup, k_componentsStr, components);
1068 
1069  OgOAttribute<uint8_t> bitsAttr(layerGroup, k_bitsPerComponentStr, bits);
1070 
1071  OgOAttribute<uint8_t> blockOrderAttr(layerGroup, k_blockOrderStr,
1072  field->m_blockOrder);
1073 
1074  OgOAttribute<uint32_t> numBlocksAttr(layerGroup, k_numBlocksStr, numBlocks);
1075 
1076  OgOAttribute<veci32_t> blockResAttr(layerGroup, k_blockResStr, blockRes);
1077 
1078  OgOAttribute<uint8_t> isCompressedAttr(layerGroup, k_isCompressed, 1);
1079 
1080  // Write the isAllocated array
1081  std::vector<uint8_t> isAllocated(numBlocks);
1082  for (size_t i = 0; i < numBlocks; ++i) {
1083  isAllocated[i] = static_cast<uint8_t>(blocks[i].isAllocated);
1084  }
1085  OgODataset<uint8_t> isAllocatedData(layerGroup, "block_is_allocated_data");
1086  isAllocatedData.addData(numBlocks, &isAllocated[0]);
1087 
1088  // Write the emptyValue array
1089  std::vector<Data_T> emptyValue(numBlocks);
1090  for (size_t i = 0; i < numBlocks; ++i) {
1091  emptyValue[i] = static_cast<Data_T>(blocks[i].emptyValue);
1092  }
1093  OgODataset<Data_T> emptyValueData(layerGroup, "block_empty_value_data");
1094  emptyValueData.addData(numBlocks, &emptyValue[0]);
1095 
1096  // Count the number of occupied blocks
1097  int occupiedBlocks = 0;
1098  for (size_t i = 0; i < numBlocks; ++i) {
1099  if (blocks[i].isAllocated) {
1100  occupiedBlocks++;
1101  }
1102  }
1103  OgOAttribute<uint32_t> numOccupiedBlockAttr(layerGroup,
1104  k_numOccupiedBlocksStr,
1105  occupiedBlocks);
1106 
1107  // Add data to file ---
1108 
1109  // Create the compressed dataset regardless of whether there are blocks
1110  // to write.
1111  OgOCDataset<Data_T> data(layerGroup, k_dataStr);
1112  // Write data if there is any
1113  if (occupiedBlocks > 0) {
1114  // Threading state
1115  ThreadingState<Data_T> state(data, blocks, numVoxels, numBlocks,
1116  isAllocated);
1117  // Number of threads
1118  const size_t numThreads = numIOThreads();
1119  // Launch threads
1120  boost::thread_group threads;
1121  for (size_t i = 0; i < numThreads; ++i) {
1122  threads.create_thread(WriteBlockOp<Data_T>(state, i));
1123  }
1124  threads.join_all();
1125  }
1126 
1127  return true;
1128 }
1129 
1130 //----------------------------------------------------------------------------//
1131 
1132 template <class Data_T>
1133 bool SparseFieldIO::readData(hid_t location,
1134  int numBlocks,
1135  const std::string &filename,
1136  const std::string &layerPath,
1137  typename SparseField<Data_T>::Ptr result)
1138 {
1139  using namespace std;
1140  using namespace Exc;
1141  using namespace Hdf5Util;
1142  using namespace Sparse;
1143 
1144  int occupiedBlocks;
1145 
1146  bool dynamicLoading = SparseFileManager::singleton().doLimitMemUse();
1147 
1148  int components = FieldTraits<Data_T>::dataDims();
1149  int numVoxels = (1 << (result->m_blockOrder * 3));
1150  int valuesPerBlock = numVoxels * components;
1151 
1152  // Read the number of occupied blocks ---
1153 
1154  if (!readAttribute(location, k_numOccupiedBlocksStr, 1, occupiedBlocks))
1155  throw MissingAttributeException("Couldn't find attribute: " +
1156  k_numOccupiedBlocksStr);
1157 
1158  // Set up the dynamic read info ---
1159 
1160  if (dynamicLoading) {
1161  // Set up the field reference
1162  result->addReference(filename, layerPath,
1163  valuesPerBlock, numVoxels,
1164  occupiedBlocks);
1165  }
1166 
1167  // Read the block info data sets ---
1168 
1169  SparseBlock<Data_T> *blocks = result->m_blocks;
1170 
1171  // ... Read the isAllocated array
1172 
1173  {
1174  vector<char> isAllocated(numBlocks);
1175  readSimpleData<char>(location, "block_is_allocated_data", isAllocated);
1176  for (int i = 0; i < numBlocks; ++i) {
1177  blocks[i].isAllocated = isAllocated[i];
1178  if (!dynamicLoading && isAllocated[i]) {
1179  blocks[i].resize(numVoxels);
1180  }
1181  }
1182  }
1183 
1184  // ... Read the emptyValue array ---
1185 
1186  {
1187  vector<Data_T> emptyValue(numBlocks);
1188  readSimpleData<Data_T>(location, "block_empty_value_data", emptyValue);
1189  for (int i = 0; i < numBlocks; ++i) {
1190  blocks[i].emptyValue = emptyValue[i];
1191  }
1192  }
1193 
1194  // Read the data ---
1195 
1196  if (occupiedBlocks > 0) {
1197 
1198  if (dynamicLoading) {
1199 
1200  result->setupReferenceBlocks();
1201 
1202  } else {
1203 
1204  size_t b = 0, bend = b + numBlocks;
1205 
1206  SparseDataReader<Data_T> reader(location, valuesPerBlock, occupiedBlocks);
1207 
1208  // We'll read at most 50meg at a time
1209  static const long maxMemPerPass = 50*1024*1024;
1210 
1211  for (int nextBlockIdx = 0;;) {
1212 
1213  long mem = 0;
1214  std::vector<Data_T*> memoryList;
1215 
1216  for (; b != bend && mem < maxMemPerPass; ++b) {
1217  if (blocks[b].isAllocated) {
1218  mem += sizeof(Data_T)*numVoxels;
1219  memoryList.push_back(blocks[b].data);
1220  }
1221  }
1222 
1223  // all done.
1224  if (!memoryList.size()) {
1225  break;
1226  }
1227 
1228  reader.readBlockList(nextBlockIdx, memoryList);
1229  nextBlockIdx += memoryList.size();
1230  }
1231 
1232  }
1233 
1234  } // if occupiedBlocks > 0
1235 
1236  return true;
1237 
1238 }
1239 
1240 //----------------------------------------------------------------------------//
1241 
1243 
1244 //----------------------------------------------------------------------------//
F3DVec64
Definition: Traits.h:148
F3DFloat64
Definition: Traits.h:143
F3DFloat32
Definition: Traits.h:142
SparseField::m_blocks
Block * m_blocks
Array of blocks. Not using std::vector since SparseBlock is noncopyable.
Definition: SparseField.h:616
FieldRes::dataWindow
const Box3i & dataWindow() const
Returns the data window. Any coordinate inside this window is safe to pass to value() in the Field su...
Definition: Field.h:253
Hdf5Util::writeAttribute
FIELD3D_API bool writeAttribute(hid_t location, const std::string &attrName, const std::string &value)
Writes a string attribute.
V3i
Imath::V3i V3i
Definition: SpiMathLib.h:71
F3DFloat16
Definition: Traits.h:141
OgSparseDataReader
Definition: SparseFile.h:86
SparseField::setupReferenceBlocks
void setupReferenceBlocks()
Internal function to setup the Reference's block pointers, for use with dynamic reading.
Definition: SparseField.h:1413
F3DVec32
Definition: Traits.h:147
Sparse::SparseBlock::emptyValue
Data_T emptyValue
The value to use if the block isn't allocated. We allow setting this per block so that we for example...
Definition: SparseField.h:308
DataTypeTraits::h5type
static hid_t h5type()
Msg::SevWarning
Definition: Log.h:68
Types.h
Contains typedefs for the commonly used types in Field3D.
Sparse::SparseBlock
Definition: SparseField.h:227
OgIAttribute
Definition: OgawaFwd.h:62
SparseFileManager::doLimitMemUse
bool doLimitMemUse() const
Returns whether to limit memory usage and do dynamic loading for sparse fields.
Definition: SparseFile.cpp:83
SparseField::m_blockOrder
int m_blockOrder
Block order (size = 2^blockOrder)
Definition: SparseField.h:610
DataTypeFloat
Definition: Traits.h:112
DataTypeEnum
DataTypeEnum
Definition: Traits.h:108
OgODataset
Definition: OgawaFwd.h:69
SparseField::Ptr
boost::intrusive_ptr< SparseField > Ptr
Definition: SparseField.h:357
OgOAttribute
Definition: OgawaFwd.h:64
FieldBase::Ptr
boost::intrusive_ptr< FieldBase > Ptr
Definition: Field.h:97
F3DVec16
Definition: Traits.h:146
DataTypeVecHalf
Definition: Traits.h:114
SparseField
This Field subclass stores voxel data in block-allocated arrays.
Definition: SparseField.h:350
SparseField::addReference
void addReference(const std::string &filename, const std::string &layerPath, int valuesPerBlock, int numVoxels, int occupiedBlocks)
Internal function to create a Reference for the current field, for use in dynamic reading.
Definition: SparseField.h:1379
DataTypeHalf
Definition: Traits.h:109
DataTypeTraits::h5bits
static int h5bits()
field_dynamic_cast
Field_T::Ptr field_dynamic_cast(RefBase::Ptr field)
Dynamic cast that uses string-comparison in order to be safe even after an object crosses a shared li...
Definition: RefCount.h:256
Sparse::SparseBlock::resize
void resize(int n)
Alloc data.
Definition: SparseField.h:259
Sparse
Namespace for sparse field specifics.
Definition: SparseField.h:221
SparseDataReader
This class gets used by SparseFieldIO and SparseFileManager to read the block data....
Definition: SparseDataReader.h:70
Hdf5Util::H5ScopedScreate
Scoped object - creates a dataspace on creation and closes it on destruction.
Definition: Hdf5Util.h:234
numIOThreads
FIELD3D_API size_t numIOThreads()
Returns the number of I/O threads to use.
Definition: InitIO.cpp:92
DataTypeVecDouble
Definition: Traits.h:116
FIELD3D_NAMESPACE_SOURCE_CLOSE
#define FIELD3D_NAMESPACE_SOURCE_CLOSE
Definition: ns.h:60
DataTypeVecFloat
Definition: Traits.h:115
InitIO.h
Contains the initIO function.
Exc
Namespace for Exception objects.
Definition: Exception.h:57
DataTypeDouble
Definition: Traits.h:113
Hdf5Util::H5ScopedDcreate
Scoped object - creates a dataset on creation and closes it on destruction.
Definition: Hdf5Util.h:263
Sparse::SparseBlock::isAllocated
bool isAllocated
Whether the block is allocated or not.
Definition: SparseField.h:303
FieldRes::extents
const Box3i & extents() const
Returns the extents of the data. This signifies the relevant area that the data exists over....
Definition: Field.h:249
Hdf5Util::readAttribute
FIELD3D_API bool readAttribute(hid_t location, const std::string &attrName, std::string &value)
Reads a string attribute.
Hdf5Util
Contains utility functions and classes for Hdf5 files.
Definition: Hdf5Util.h:86
SparseFileManager::singleton
static SparseFileManager & singleton()
Returns a reference to the singleton instance.
Definition: SparseFile.cpp:66
Hdf5Util::checkHdf5Gzip
FIELD3D_API bool checkHdf5Gzip()
Checks whether gzip is available in the current hdf5 library.
Definition: Hdf5Util.cpp:722
DataTypeTraits
Definition: Traits.h:266
OgIDataset
Definition: OgawaFwd.h:67
FIELD3D_NAMESPACE_OPEN
Definition: FieldMapping.cpp:74
Box3i
Imath::Box3i Box3i
Definition: SpiMathLib.h:77
Msg::print
FIELD3D_API void print(Severity severity, const std::string &message)
Sends the string to the assigned output, prefixing the message with the severity.
Definition: Log.cpp:70
SparseField::m_blockRes
V3i m_blockRes
Block array resolution.
Definition: SparseField.h:612
veci32_t
Field3D::V3i veci32_t
Definition: Traits.h:94
OgDataType
OgDataType
Enumerates the various uses for Ogawa-level groups.
Definition: Traits.h:125
FieldTraits::dataDims
static int dataDims()
Definition: Traits.h:178
Sparse::SparseBlock::data
Data_T * data
Pointer to data. Null if block is unallocated.
Definition: SparseField.h:311