kspaceFirstOrder3D-OMP  1.1
The C++ implementation of the k-wave toolbox for the time-domain simulation of acoustic wave fields in 3D
 All Classes Files Functions Variables Typedefs Enumerations Friends Pages
OutputHDF5Stream.cpp
Go to the documentation of this file.
1 /**
2  * @file OutputHDF5Stream.cpp
3  * @author Jiri Jaros \n
4  * Faculty of Information Technology\n
5  * Brno University of Technology \n
6  * jarosjir@fit.vutbr.cz
7  *
8  * @brief The implementation file of classes responsible for storing output
9  * quantities into the output HDF5 file
10  *
11  * @version kspaceFirstOrder3D 2.15
12  *
13  * @date 11 July 2012, 10:30 (created) \n
14  * 26 September 2014, 18:36 (revised)
15  *
16  * @section License
17  * This file is part of the C++ extension of the k-Wave Toolbox (http://www.k-wave.org).\n
18  * Copyright (C) 2014 Jiri Jaros and Bradley Treeby
19  *
20  * This file is part of k-Wave. k-Wave is free software: you can redistribute it
21  * and/or modify it under the terms of the GNU Lesser General Public License as
22  * published by the Free Software Foundation, either version 3 of the License,
23  * or (at your option) any later version.
24  *
25  * k-Wave is distributed in the hope that it will be useful, but
26  * WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
28  * See the GNU Lesser General Public License for more details.
29  *
30  * You should have received a copy of the GNU Lesser General Public License
31  * along with k-Wave. If not, see <http://www.gnu.org/licenses/>.
32  */
33 
34 
35 #include <string.h>
36 #include <cmath>
37 #include <immintrin.h>
39 
40 #include <Parameters/Parameters.h>
41 #include <Utils/ErrorMessages.h>
42 #include <limits>
43 
44 
45 using namespace std;
46 
47 //----------------------------------------------------------------------------//
48 // Constants //
49 //----------------------------------------------------------------------------//
50 
51 
52 
53 //----------------------------------------------------------------------------//
54 // Definitions //
55 //----------------------------------------------------------------------------//
56 
57 
58 //----------------------------------------------------------------------------//
59 // TBaseOutputHDF5Stream implementation //
60 // public methods //
61 //----------------------------------------------------------------------------//
62 
63 
64 /**
65  * Apply post-processing on the buffer. It supposes the elements are independent.
66  *
67  */
69 {
70  switch (ReductionOp)
71  {
72  case roNONE :
73  {
74  // do nothing
75  break;
76  }
77 
78  case roRMS :
79  {
80  const float ScalingCoeff = 1.0f / (TParameters::GetInstance()->Get_Nt() - TParameters::GetInstance()->GetStartTimeIndex());
81 
82  #pragma omp parallel for if (BufferSize > MinGridpointsToSampleInParallel)
83  for (size_t i = 0; i < BufferSize; i++)
84  {
85  StoreBuffer[i] = sqrt(StoreBuffer[i] * ScalingCoeff);
86  }
87  break;
88  }
89 
90  case roMAX :
91  {
92  // do nothing
93  break;
94  }
95 
96  case roMIN :
97  {
98  // do nothing
99  break;
100  }
101  }// switch
102 
103 }// end of ApplyPostProcessing
104 //------------------------------------------------------------------------------
105 
106 
107 
108 //----------------------------------------------------------------------------//
109 // TBaseOutputHDF5Stream implementation //
110 // public methods //
111 //----------------------------------------------------------------------------//
112 
113 
114 /**
115  * Allocate memory using a proper memory alignment.
116  * @warning This can routine is not used in the base class (should be used in
117  * derived ones).
118  */
120 {
121  StoreBuffer = (float *) _mm_malloc(BufferSize * sizeof (float), DATA_ALIGNMENT);
122 
123  if (!StoreBuffer)
124  {
125  fprintf(stderr, Matrix_ERR_FMT_NotEnoughMemory, "TBaseOutputHDF5Stream");
126  throw bad_alloc();
127  }
128 
129  // we need different initialization for different reduction ops
130  switch (ReductionOp)
131  {
132  case roNONE :
133  {
134  // zero the matrix
135  #pragma omp parallel for if (BufferSize > MinGridpointsToSampleInParallel)
136  for (size_t i = 0; i < BufferSize; i++)
137  {
138  StoreBuffer[i] = 0.0f;
139  }
140  break;
141  }
142 
143  case roRMS :
144  {
145  // zero the matrix
146  #pragma omp parallel for if (BufferSize > MinGridpointsToSampleInParallel)
147  for (size_t i = 0; i < BufferSize; i++)
148  {
149  StoreBuffer[i] = 0.0f;
150  }
151  break;
152  }
153 
154  case roMAX :
155  {
156  // set the values to the highest negative float value
157  #pragma omp parallel for if (BufferSize > MinGridpointsToSampleInParallel)
158  for (size_t i = 0; i < BufferSize; i++)
159  {
160  StoreBuffer[i] = -1 * std::numeric_limits<float>::max();
161  }
162  break;
163  }
164 
165  case roMIN :
166  {
167  // set the values to the highest float value
168  #pragma omp parallel for if (BufferSize > MinGridpointsToSampleInParallel)
169  for (size_t i = 0; i < BufferSize; i++)
170  {
171  StoreBuffer[i] = std::numeric_limits<float>::max();
172  }
173  break;
174  }
175  }// switch
176 }// end of AllocateMemory
177 //------------------------------------------------------------------------------
178 
179 /**
180  * Free memory.
181  * @warning This can routine is not used in the base class (should be used in
182  * derived ones).
183  */
185 {
186  if (StoreBuffer)
187  {
188  _mm_free(StoreBuffer);
189  StoreBuffer = NULL;
190  }
191 }// end of FreeMemory
192 //------------------------------------------------------------------------------
193 
194 
195 //----------------------------------------------------------------------------//
196 // TIndexOutputHDF5Stream implementation //
197 // public methods //
198 //----------------------------------------------------------------------------//
199 
200 /**
201  * Constructor - links the HDF5 dataset, source (sampled matrix), Sensor mask
202  * and the reduction operator together. The constructor DOES NOT allocate memory
203  * because the size of the sensor mask is not known at the time the instance of
204  * the class is being created.
205  *
206  * @param [in] HDF5_File - Handle to the HDF5 (output) file
207  * @param [in] HDF5_ObjectName - The dataset's name (index based sensor data
208  * is store in a single dataset)
209  * @param [in] SourceMatrix - The source matrix (only real matrices are
210  * supported)
211  * @param [in] SensorMask - Index based sensor mask
212  * @param [in] ReductionOp - Reduction operator
213  * @param [in] BufferToReuse - An external buffer can be used to line up
214  * the grid points
215  */
217  const char * HDF5_ObjectName,
218  const TRealMatrix & SourceMatrix,
219  const TIndexMatrix & SensorMask,
220  const TReductionOperator ReductionOp,
221  float * BufferToReuse)
222  : TBaseOutputHDF5Stream(HDF5_File, HDF5_ObjectName, SourceMatrix, ReductionOp, BufferToReuse),
223  SensorMask(SensorMask),
224  HDF5_DatasetId(H5I_BADID),
225  SampledTimeStep(0)
226 {
227 
228 }// end of TIndexOutputHDF5Stream
229 //------------------------------------------------------------------------------
230 
231 
232 /**
233  * Destructor.
234  * if the file is still opened, it applies the post processing and flush the data.
235  * Then, the object memory is freed and the object destroyed.
236  */
238 {
239  Close();
240  // free memory only if it was allocated
241  if (!BufferReuse) FreeMemory();
242 }// end of Destructor
243 //------------------------------------------------------------------------------
244 
245 
246 
247 /**
248  * Create a HDF5 stream, create a dataset, and allocate data for it.
249  */
251 {
252  size_t NumberOfSampledElementsPerStep = SensorMask.GetTotalElementCount();
253 
255 
256  // Derive dataset dimension sizes
257  TDimensionSizes DatasetSize(NumberOfSampledElementsPerStep,
258  (ReductionOp == roNONE) ? Params->Get_Nt() - Params->GetStartTimeIndex() : 1,
259  1);
260 
261  // Set HDF5 chunk size
262  TDimensionSizes ChunkSize(NumberOfSampledElementsPerStep, 1, 1);
263  // for chunks bigger than 32 MB
264  if (NumberOfSampledElementsPerStep > (ChunkSize_4MB * 8))
265  {
266  ChunkSize.X = ChunkSize_4MB; // set chunk size to MB
267  }
268 
269  // Create a dataset under the root group
272  DatasetSize,
273  ChunkSize,
274  Params->GetCompressionLevel());
275 
276  // Write dataset parameters
279  THDF5_File::hdf5_mdt_real);
282  THDF5_File::hdf5_mdt_float);
283 
284 
285  // Sampled time step
286  SampledTimeStep = 0;
287 
288  // Set buffer size
289  BufferSize = NumberOfSampledElementsPerStep;
290 
291  // Allocate memory if needed
292  if (!BufferReuse) AllocateMemory();
293 }// end of Create
294 //------------------------------------------------------------------------------
295 
296 /**
297  * Reopen the output stream after restart.
298  */
300 {
301  // Get parameters
303 
304  // Set buffer size
306 
307  // Allocate memory if needed
308  if (!BufferReuse) AllocateMemory();
309 
310  // Reopen the dataset
313 
314 
315  if (ReductionOp == roNONE)
316  { // raw time series - just seek to the right place in the dataset
317  SampledTimeStep = ((Params->Get_t_index() - Params->GetStartTimeIndex()) < 0) ?
318  0 : (Params->Get_t_index() - Params->GetStartTimeIndex());
319 
320  }
321  else
322  { // aggregated quantities - reload data
323  SampledTimeStep = 0;
324 
325  // Since there is only a single timestep in the dataset, I can read the whole dataset
329  StoreBuffer);
330  }
331 }// end of Reopen
332 //------------------------------------------------------------------------------
333 
334 
335 /**
336  * Sample grid points, line them up in the buffer an flush to the disk unless a
337  * reduction operator is applied.
338  */
340 {
341  const float * SourceData = SourceMatrix.GetRawData();
342  const size_t * SensorData = SensorMask.GetRawData();
343 
344  switch (ReductionOp)
345  {
346  case roNONE :
347  {
348  #pragma omp parallel for if (BufferSize > MinGridpointsToSampleInParallel)
349  for (size_t i = 0; i < BufferSize; i++)
350  {
351  StoreBuffer[i] = SourceData[SensorData[i]];
352  }
353  // only raw time series are flushed down to the disk every time step
355  /* - for future use when offloading the sampling work to HDF5 - now it seem to be slower
356  HDF5_File.WriteSensorbyMaskToHyperSlab(HDF5_DatasetId,
357  Position, // position in the dataset
358  BufferSize, // number of elements sampled
359  SensorMask.GetRawData(), // Sensor
360  SourceMatrix.GetDimensionSizes(), // Matrix dims
361  SourceMatrix.GetRawData());
362  Position.Y++;
363  */
364  break;
365  }// case roNONE
366 
367  case roRMS :
368  {
369  #pragma omp parallel for if (BufferSize > MinGridpointsToSampleInParallel)
370  for (size_t i = 0; i < BufferSize; i++)
371  {
372  StoreBuffer[i] += (SourceData[SensorData[i]] * SourceData[SensorData[i]]);
373  }
374  break;
375  }// case roRMS
376 
377  case roMAX :
378  {
379  #pragma omp parallel for if (BufferSize > MinGridpointsToSampleInParallel)
380  for (size_t i = 0; i < BufferSize; i++)
381  {
382  if (StoreBuffer[i] < SourceData[SensorData[i]])
383  StoreBuffer[i] = SourceData[SensorData[i]];
384  }
385  break;
386  }// case roMAX
387 
388  case roMIN :
389  {
390  #pragma omp parallel for if (BufferSize > MinGridpointsToSampleInParallel)
391  for (size_t i = 0; i < BufferSize; i++)
392  {
393  if (StoreBuffer[i] > SourceData[SensorData[i]])
394  StoreBuffer[i] = SourceData[SensorData[i]];
395  }
396  break;
397  } //case roMIN
398  }// switch
399 }// end of Sample
400 //------------------------------------------------------------------------------
401 
402 /**
403  * Apply post-processing on the buffer and flush it to the file.
404  */
406 {
407  // run inherited method
409  // When no reduction operator is applied, the data is flushed after every time step
410  if (ReductionOp != roNONE) FlushBufferToFile();
411 }// end of PostProcessing
412 //------------------------------------------------------------------------------
413 
414 
415 /**
416  * Checkpoint the stream and close.
417  */
419 {
420  // raw data has already been flushed, others has to be fushed here
421  if (ReductionOp != roNONE) FlushBufferToFile();
422 
423 }// end of Checkpoint
424 //------------------------------------------------------------------------------
425 
426 /**
427  * Close stream (apply post-processing if necessary, flush data and close).
428  */
430 {
431  // the dataset is still opened
432  if (HDF5_DatasetId != H5I_BADID)
433  {
435  }
436 
437  HDF5_DatasetId = H5I_BADID;
438 }// end of Close
439 //------------------------------------------------------------------------------
440 
441 //----------------------------------------------------------------------------//
442 // TIndexOutputHDF5Stream implementation //
443 // protected methods //
444 //----------------------------------------------------------------------------//
445 
446 
447 /**
448  * Flush the buffer down to the file at the actual position.
449  */
451 {
455  StoreBuffer);
456  SampledTimeStep++;
457 }// end of FlushToFile
458 //------------------------------------------------------------------------------
459 
460 
461 
462 
463 
464 
465 //----------------------------------------------------------------------------//
466 // TCuboidOutputHDF5Stream implementation //
467 // public methods //
468 //----------------------------------------------------------------------------//
469 
470 
471 /**
472  * Constructor - links the HDF5 dataset, SourceMatrix, and SensorMask together.
473  * @param [in] HDF5_File - HDF5 file to write the output to
474  * @param [in] HDF5_GroupName - The name of the HDF5 group. This group contains datasets for particular cuboids
475  * @param [in] SourceMatrix - Source matrix to be sampled
476  * @param [in] SensorMask - Sensor mask with the cuboid coordinates
477  * @param [in] ReductionOp - Reduction operator
478  * @param [in] BufferToReuse - If there is a memory space to be reused, provide a pointer
479  */
481  const char * HDF5_GroupName,
482  const TRealMatrix & SourceMatrix,
483  const TIndexMatrix & SensorMask,
484  const TReductionOperator ReductionOp,
485  float * BufferToReuse)
486  : TBaseOutputHDF5Stream(HDF5_File, HDF5_GroupName, SourceMatrix, ReductionOp, BufferToReuse),
487  SensorMask(SensorMask),
488  HDF5_GroupId(H5I_BADID),
489  SampledTimeStep(0)
490 {
491 
492 }// end of TCubodidOutputHDF5Stream
493 //------------------------------------------------------------------------------
494 
495 
496 /**
497  * Destructor.
498  * if the file is still opened, it applies the post processing and flush the data.
499  * Then, the object memory is freed and the object destroyed.
500  */
502 {
503  Close();
504 
505  // free memory only if it was allocated
506  if (!BufferReuse) FreeMemory();
507 }// end ~TCubodidOutputHDF5Stream
508 //------------------------------------------------------------------------------
509 
510 
511 /**
512  * Create a HDF5 stream and allocate data for it. It also creates a HDF5 group
513  * with particular datasets (one per cuboid).
514  */
516 {
517  // Create the HDF5 group and open it
519 
520  // Create all datasets (sizes, chunks, and attributes)
521  size_t NumberOfCuboids = SensorMask.GetDimensionSizes().Y;
522  CuboidsInfo.reserve(NumberOfCuboids);
523  size_t ActualPositionInBuffer = 0;
524 
525  for (size_t CuboidIndex = 0; CuboidIndex < NumberOfCuboids; CuboidIndex++)
526  {
527  TCuboidInfo CuboidInfo;
528 
529  CuboidInfo.HDF5_CuboidId = CreateCuboidDataset(CuboidIndex);
530  CuboidInfo.StartingPossitionInBuffer = ActualPositionInBuffer;
531  CuboidsInfo.push_back(CuboidInfo);
532 
533  ActualPositionInBuffer += (SensorMask.GetBottomRightCorner(CuboidIndex) - SensorMask.GetTopLeftCorner(CuboidIndex)).GetElementCount();
534  }
535 
536  //we're at the beginning
537  SampledTimeStep = 0;
538 
539  // Create the memory buffer if necessary and set starting address
541 
542  // Allocate memory if needed
543  if (!BufferReuse) AllocateMemory();
544 }// end of Create
545 //------------------------------------------------------------------------------
546 
547 
548 /**
549  * Reopen the output stream after restart and reload data.
550  */
552 {
553  // Get parameters
555 
556  SampledTimeStep = 0;
557  if (ReductionOp == roNONE) // set correct sampled timestep for raw data series
558  {
559  SampledTimeStep = ((Params->Get_t_index() - Params->GetStartTimeIndex()) < 0) ?
560  0 : (Params->Get_t_index() - Params->GetStartTimeIndex());
561  }
562 
563  // Create the memory buffer if necessary and set starting address
565 
566  // Allocate memory if needed
567  if (!BufferReuse) AllocateMemory();
568 
569 
570  // Open all datasets (sizes, chunks, and attributes)
571  size_t NumberOfCuboids = SensorMask.GetDimensionSizes().Y;
572  CuboidsInfo.reserve(NumberOfCuboids);
573  size_t ActualPositionInBuffer = 0;
574 
575  // Open the HDF5 group
577 
578  for (size_t CuboidIndex = 0; CuboidIndex < NumberOfCuboids; CuboidIndex++)
579  {
580  TCuboidInfo CuboidInfo;
581 
582  // @todo: Can be done easily with std::to_string and c++0x or c++-11
583  char HDF5_DatasetName[32] = "";
584  // Indexed from 1
585  sprintf(HDF5_DatasetName, "%ld",CuboidIndex + 1);
586 
587  // open the dataset
589  HDF5_DatasetName);
590  CuboidInfo.StartingPossitionInBuffer = ActualPositionInBuffer;
591  CuboidsInfo.push_back(CuboidInfo);
592 
593  if (ReductionOp != roNONE)
594  { // Reload data
595  TDimensionSizes CuboidSize((SensorMask.GetBottomRightCorner(CuboidIndex) - SensorMask.GetTopLeftCorner(CuboidIndex)).X,
596  (SensorMask.GetBottomRightCorner(CuboidIndex) - SensorMask.GetTopLeftCorner(CuboidIndex)).Y,
597  (SensorMask.GetBottomRightCorner(CuboidIndex) - SensorMask.GetTopLeftCorner(CuboidIndex)).Z);
598 
600  HDF5_DatasetName,
601  CuboidSize,
602  StoreBuffer + ActualPositionInBuffer);
603  }
604  // move the pointer for the next cuboid beginning
605  ActualPositionInBuffer += (SensorMask.GetBottomRightCorner(CuboidIndex) -
606  SensorMask.GetTopLeftCorner(CuboidIndex)).GetElementCount();
607  }
608 }// end of Reopen
609 //------------------------------------------------------------------------------
610 
611 /**
612  * Sample data into buffer and apply reduction, or flush to disk - based on a sensor mask.
613  */
615 {
616  const size_t XY_Size = SourceMatrix.GetDimensionSizes().Y * SourceMatrix.GetDimensionSizes().X;
617  const size_t X_Size = SourceMatrix.GetDimensionSizes().X;
618 
619  const float * SourceData = SourceMatrix.GetRawData();
620 
621  switch (ReductionOp)
622  {
623  case roNONE :
624  {
625  /* We use here direct HDF5 offload using MEMSPACE - seems to be faster for bigger datasets*/
626  TDimensionSizes DatasetPosition(0,0,0,0); //4D position in the dataset
627  TDimensionSizes CuboidSize(0,0,0,0); // Size of the cuboid
628 
629  DatasetPosition.T = SampledTimeStep;
630  const float * MatrixData = SourceMatrix.GetRawData();
631 
632  // iterate over all cuboid to be sampled
633  for (size_t CuboidIndex = 0; CuboidIndex < CuboidsInfo.size(); CuboidIndex++)
634  {
635  CuboidSize = SensorMask.GetBottomRightCorner(CuboidIndex) - SensorMask.GetTopLeftCorner(CuboidIndex);
636  CuboidSize.T = 1;
637 
638  HDF5_File.WriteCuboidToHyperSlab(CuboidsInfo[CuboidIndex].HDF5_CuboidId,
639  DatasetPosition,
640  SensorMask.GetTopLeftCorner(CuboidIndex), // position in the SourceMatrix
641  CuboidSize,
643  MatrixData);
644  }
645  SampledTimeStep++; // Move forward in time
646 
647  break;
648 
649  /* At the time being, this version using manual data lining up seems to be slower, and is not used
650  size_t BufferStart = 0;
651 
652  for (size_t CuboidIdx = 0; CuboidIdx < SensorMask.GetDimensionSizes().Y; CuboidIdx++)
653  {
654  const TDimensionSizes TopLeftCorner = SensorMask.GetTopLeftCorner(CuboidIdx);
655  const TDimensionSizes BottomRightCorner = SensorMask.GetBottomRightCorner(CuboidIdx);
656 
657  size_t cuboid_XY_plane_size = ( BottomRightCorner.Y - TopLeftCorner.Y) * ( BottomRightCorner.X - TopLeftCorner.X);
658  size_t cuboid_X_plane_size = ( BottomRightCorner.X - TopLeftCorner.X);
659 
660  #pragma omp parallel for collapse(3)
661  for (size_t z = TopLeftCorner.Z; z <= BottomRightCorner.Z; z++)
662  for (size_t y = TopLeftCorner.Y; y <= BottomRightCorner.Y; y++)
663  for (size_t x = TopLeftCorner.X; x <= BottomRightCorner.X; x++)
664  {
665  StoreBuffer[BufferStart +
666  (z - TopLeftCorner.Z) * cuboid_XY_plane_size +
667  (y - TopLeftCorner.Y) * cuboid_X_plane_size +
668  (x - TopLeftCorner.X) ]
669 
670  = SourceMatrix[z * XY_Size + y * X_Size + x];
671  }
672  BufferStart += (BottomRightCorner - TopLeftCorner).GetElementCount();
673  }
674  FlushBufferToFile();
675  break;
676  */
677  }// case roNONE
678 
679  case roRMS :
680  {
681  size_t CuboidInBufferStart = 0;
682 
683  // Parallelise within the cuboid - Since a typical number of cuboids is 1, than we have to paralelise inside
684  for (size_t CuboidIdx = 0; CuboidIdx < SensorMask.GetDimensionSizes().Y; CuboidIdx++)
685  {
686  const TDimensionSizes TopLeftCorner = SensorMask.GetTopLeftCorner(CuboidIdx);
687  const TDimensionSizes BottomRightCorner = SensorMask.GetBottomRightCorner(CuboidIdx);
688 
689  size_t cuboid_XY_plane_size = (BottomRightCorner.Y - TopLeftCorner.Y + 1) *
690  (BottomRightCorner.X - TopLeftCorner.X + 1);
691  size_t cuboid_X_plane_size = (BottomRightCorner.X - TopLeftCorner.X + 1);
692 
693  #pragma omp parallel for collapse(3) \
694  if ((BottomRightCorner - TopLeftCorner).GetElementCount() > MinGridpointsToSampleInParallel)
695  for (size_t z = TopLeftCorner.Z; z <= BottomRightCorner.Z; z++)
696  for (size_t y = TopLeftCorner.Y; y <= BottomRightCorner.Y; y++)
697  for (size_t x = TopLeftCorner.X; x <= BottomRightCorner.X; x++)
698  {
699  const size_t StoreBufferIndex = CuboidInBufferStart +
700  (z - TopLeftCorner.Z) * cuboid_XY_plane_size +
701  (y - TopLeftCorner.Y) * cuboid_X_plane_size +
702  (x - TopLeftCorner.X);
703 
704  const size_t SourceIndex = z * XY_Size + y * X_Size + x;
705 
706  // aggregating the sum over timesteps
707  StoreBuffer[StoreBufferIndex] += (SourceData[SourceIndex] * SourceData[SourceIndex]);
708  }
709 
710  CuboidInBufferStart += (BottomRightCorner - TopLeftCorner).GetElementCount();
711  }
712 
713  break;
714  }// case roRMS
715 
716  case roMAX :
717  {
718  size_t CuboidInBufferStart = 0;
719 
720  // Parallelise within the cuboid - Since a typical number of cuboids is 1, than we have to paralelise inside.
721  for (size_t CuboidIdx = 0; CuboidIdx < SensorMask.GetDimensionSizes().Y; CuboidIdx++)
722  {
723  const TDimensionSizes TopLeftCorner = SensorMask.GetTopLeftCorner(CuboidIdx);
724  const TDimensionSizes BottomRightCorner = SensorMask.GetBottomRightCorner(CuboidIdx);
725 
726  size_t cuboid_XY_plane_size = (BottomRightCorner.Y - TopLeftCorner.Y + 1) *
727  (BottomRightCorner.X - TopLeftCorner.X + 1);
728  size_t cuboid_X_plane_size = (BottomRightCorner.X - TopLeftCorner.X + 1);
729 
730  #pragma omp parallel for collapse(3) \
731  if ((BottomRightCorner - TopLeftCorner).GetElementCount() > MinGridpointsToSampleInParallel)
732  for (size_t z = TopLeftCorner.Z; z <= BottomRightCorner.Z; z++)
733  for (size_t y = TopLeftCorner.Y; y <= BottomRightCorner.Y; y++)
734  for (size_t x = TopLeftCorner.X; x <= BottomRightCorner.X; x++)
735  {
736  const size_t StoreBufferIndex = CuboidInBufferStart +
737  (z - TopLeftCorner.Z) * cuboid_XY_plane_size +
738  (y - TopLeftCorner.Y) * cuboid_X_plane_size +
739  (x - TopLeftCorner.X);
740 
741  const size_t SourceIndex = z * XY_Size + y * X_Size + x;
742 
743  // finding max
744  if (StoreBuffer[StoreBufferIndex] < SourceData[SourceIndex])
745  {
746  StoreBuffer[StoreBufferIndex] = SourceData[SourceIndex];
747  }
748  }
749  CuboidInBufferStart += (BottomRightCorner - TopLeftCorner).GetElementCount();
750  }
751  break;
752  }// case roMAX
753 
754  case roMIN :
755  {
756  size_t CuboidInBufferStart = 0;
757 
758  // Parallelise within the cuboid - Since a typical number of cuboids is 1, than we have to paralelise inside.
759  for (size_t CuboidIdx = 0; CuboidIdx < SensorMask.GetDimensionSizes().Y; CuboidIdx++)
760  {
761  const TDimensionSizes TopLeftCorner = SensorMask.GetTopLeftCorner(CuboidIdx);
762  const TDimensionSizes BottomRightCorner = SensorMask.GetBottomRightCorner(CuboidIdx);
763 
764  size_t cuboid_XY_plane_size = (BottomRightCorner.Y - TopLeftCorner.Y + 1) *
765  (BottomRightCorner.X - TopLeftCorner.X + 1);
766  size_t cuboid_X_plane_size = (BottomRightCorner.X - TopLeftCorner.X + 1);
767 
768  #pragma omp parallel for collapse(3) \
769  if ((BottomRightCorner - TopLeftCorner).GetElementCount() > MinGridpointsToSampleInParallel)
770  for (size_t z = TopLeftCorner.Z; z <= BottomRightCorner.Z; z++)
771  for (size_t y = TopLeftCorner.Y; y <= BottomRightCorner.Y; y++)
772  for (size_t x = TopLeftCorner.X; x <= BottomRightCorner.X; x++)
773  {
774  const size_t StoreBufferIndex = CuboidInBufferStart +
775  (z - TopLeftCorner.Z) * cuboid_XY_plane_size +
776  (y - TopLeftCorner.Y) * cuboid_X_plane_size +
777  (x - TopLeftCorner.X);
778  const size_t SourceIndex = z * XY_Size + y * X_Size + x;
779 
780  // finding min
781  if (StoreBuffer[StoreBufferIndex] > SourceData[SourceIndex])
782  {
783  StoreBuffer[StoreBufferIndex] = SourceData[SourceIndex];
784  }
785  }
786  CuboidInBufferStart += (BottomRightCorner - TopLeftCorner).GetElementCount();
787  }
788 
789  break;
790  }// case roMIN
791  }// switch
792 }// end of Sample
793 //------------------------------------------------------------------------------
794 
795 
796 /**
797  * Apply post-processing on the buffer and flush it to the file.
798  */
800 {
801  // run inherited method
803  // When no reduction operator is applied, the data is flushed after every time step
804  if (ReductionOp != roNONE) FlushBufferToFile();
805 }// end of PostProcessing
806 //------------------------------------------------------------------------------
807 
808 /**
809  * Checkpoint the stream.
810  */
812 {
813  // raw data has already been flushed, others has to be fushed here
814  if (ReductionOp != roNONE) FlushBufferToFile();
815 }// end of Checkpoint
816 //------------------------------------------------------------------------------
817 
818 
819 /**
820  * Close stream (apply post-processing if necessary, flush data, close datasets
821  * and the group).
822  */
824 {
825  // the group is still open
826  if (HDF5_GroupId != H5I_BADID)
827  {
828  // Close all datasets and the group
829  for (size_t CuboidIndex = 0; CuboidIndex < CuboidsInfo.size(); CuboidIndex++)
830  {
831  HDF5_File.CloseDataset(CuboidsInfo[CuboidIndex].HDF5_CuboidId);
832  }
833  CuboidsInfo.clear();
834 
836  HDF5_GroupId = H5I_BADID;
837  }// if opened
838 }// end of Close
839 //------------------------------------------------------------------------------
840 
841 
842 
843 //----------------------------------------------------------------------------//
844 // TIndexOutputHDF5Stream implementation //
845 // protected methods //
846 //----------------------------------------------------------------------------//
847 
848 /**
849  * Create a new dataset for a given cuboid specified by index (order).
850  * @param [in] Index - Index of the cuboid in the sensor mask
851  * @return HDF5 handle to the dataset.
852  */
854 {
856 
857  // if time series then Number of steps else 1
858  size_t NumberOfSampledTimeSteps = (ReductionOp == roNONE)
859  ? Params->Get_Nt() - Params->GetStartTimeIndex()
860  : 0; // will be a 3D dataset
861  // Set cuboid dimensions
865  NumberOfSampledTimeSteps
866  );
867 
868  // Set chunk size
869  // If the size of the cuboid is bigger than 32 MB per timestep, set the chunk to approx 4MB
870  size_t NumberOfSlabs = 1; //at least one slab
871  TDimensionSizes CuboidChunkSize(CuboidSize.X, CuboidSize.Y, CuboidSize.Z, (ReductionOp == roNONE) ? 1 : 0);
872 
873  if (CuboidChunkSize.GetElementCount() > (ChunkSize_4MB * 8))
874  {
875  while (NumberOfSlabs * CuboidSize.X * CuboidSize.Y < ChunkSize_4MB) NumberOfSlabs++;
876  CuboidChunkSize.Z = NumberOfSlabs;
877  }
878 
879  // @todo: Can be done easily with std::to_string and c++0x or c++-11
880  char HDF5_DatasetName[32] = "";
881  // Indexed from 1
882  sprintf(HDF5_DatasetName, "%ld",Index+1);
883  hid_t HDF5_DatasetId = HDF5_File.CreateFloatDataset(HDF5_GroupId,
884  HDF5_DatasetName,
885  CuboidSize,
886  CuboidChunkSize,
887  Params->GetCompressionLevel()
888  );
889 
890  // Write dataset parameters
892  HDF5_DatasetName,
893  THDF5_File::hdf5_mdt_real);
895  HDF5_DatasetName,
896  THDF5_File::hdf5_mdt_float);
897 
898  return HDF5_DatasetId;
899 }//end of CreateCuboidDatasets
900 //------------------------------------------------------------------------------
901 
902 
903 
904 /**
905  * Flush the buffer to the file (to multiple datasets if necessary).
906  */
908 {
909  TDimensionSizes Position (0,0,0,0);
910  TDimensionSizes BlockSize(0,0,0,0);
911 
912  if (ReductionOp == roNONE) Position.T = SampledTimeStep;
913 
914  for (size_t CuboidIndex = 0; CuboidIndex < CuboidsInfo.size(); CuboidIndex++)
915  {
916 
917  BlockSize = SensorMask.GetBottomRightCorner(CuboidIndex) - SensorMask.GetTopLeftCorner(CuboidIndex);
918  BlockSize.T = 1;
919 
920  HDF5_File.WriteHyperSlab(CuboidsInfo[CuboidIndex].HDF5_CuboidId,
921  Position,
922  BlockSize,
923  StoreBuffer + CuboidsInfo[CuboidIndex].StartingPossitionInBuffer
924  );
925 
926  }
927 
928  SampledTimeStep++;
929 }// end of FlushBufferToFile
930 //------------------------------------------------------------------------------
931 
932 
933 
934 //----------------------------------------------------------------------------//
935 // TWholeDomainOutputHDF5Stream implementation //
936 // public methods //
937 //----------------------------------------------------------------------------//
938 
939 /**
940  * Constructor - links the HDF5 dataset and SourceMatrix.
941  * @param [in] HDF5_File - HDF5 file to write the output to
942  * @param [in] HDF5_DatasetName - The name of the HDF5 group. This group contains datasets for particular cuboids
943  * @param [in] SourceMatrix - Source matrix to be sampled
944  * @param [in] ReductionOp - Reduction operator
945  * @param [in] BufferToReuse - If there is a memory space to be reused, provide a pointer
946  */
948  const char * HDF5_DatasetName,
949  const TRealMatrix & SourceMatrix,
950  const TReductionOperator ReductionOp,
951  float * BufferToReuse)
952  : TBaseOutputHDF5Stream(HDF5_File, HDF5_DatasetName, SourceMatrix, ReductionOp, BufferToReuse),
953  HDF5_DatasetId(H5I_BADID),
954  SampledTimeStep(0)
955 {
956 
957 }// end of TWholeDomainOutputHDF5Stream
958 //------------------------------------------------------------------------------
959 
960 /**
961  * Destructor.
962  * if the file is still opened, it applies the post processing and flush the data.
963  * Then, the object memory is freed and the object destroyed.
964  */
966 {
967  Close();
968  // free memory only if it was allocated
969  if (!BufferReuse) FreeMemory();
970 }// end of Destructor
971 //------------------------------------------------------------------------------
972 
973 /**
974  * Create a HDF5 stream for the whole domain and allocate data for it.
975  */
977 {
979 
980  // Create a dataset under the root group
984  ChunkSize,
986 
987  // Write dataset parameters
990  THDF5_File::hdf5_mdt_real);
993  THDF5_File::hdf5_mdt_float);
994 
995  // Set buffer size
997 
998  // Allocate memory if needed
999  if (!BufferReuse) AllocateMemory();
1000 }//end of Create
1001 //------------------------------------------------------------------------------
1002 
1003 
1004 /**
1005  * Reopen the output stream after restart and reload data.
1006  */
1008 {
1010 
1011  // Set buffer size
1013 
1014  // Allocate memory if needed
1015  if (!BufferReuse) AllocateMemory();
1016 
1017  // Open the dataset under the root group
1020 
1021  SampledTimeStep = 0;
1022  if (ReductionOp == roNONE)
1023  { // seek in the dataset
1024  SampledTimeStep = ((Params->Get_t_index() - Params->GetStartTimeIndex()) < 0) ?
1025  0 : (Params->Get_t_index() - Params->GetStartTimeIndex());
1026  }
1027  else
1028  { // reload data
1032  StoreBuffer);
1033  }
1034 }// end of Reopen
1035 //------------------------------------------------------------------------------
1036 
1037 
1038 /**
1039  * Sample all grid points, line them up in the buffer an flush to the disk unless
1040  * a reduction operator is applied.
1041  */
1043 {
1044  const float * SourceData = SourceMatrix.GetRawData();
1045 
1046  switch (ReductionOp)
1047  {
1048  case roNONE :
1049  {
1050 
1051  /* We use here direct HDF5 offload using MEMSPACE - seems to be faster for bigger datasets*/
1052  const TDimensionSizes DatasetPosition(0,0,0,SampledTimeStep); //4D position in the dataset
1053 
1054  TDimensionSizes CuboidSize(SourceMatrix.GetDimensionSizes());// Size of the cuboid
1055  CuboidSize.T = 1;
1056 
1057  // iterate over all cuboid to be sampled
1059  DatasetPosition,
1060  TDimensionSizes(0,0,0,0), // position in the SourceMatrix
1061  CuboidSize,
1064 
1065  SampledTimeStep++; // Move forward in time
1066 
1067  // This version is obsolete (needs one more data movement)
1068  /*
1069  #pragma omp parallel for if (BufferSize > MinGridpointsToSampleInParallel)
1070  for (size_t i = 0; i < BufferSize; i++)
1071  {
1072  StoreBuffer[i] = SourceData[i];
1073  }
1074  // only raw time series are flushed down to the disk every time step
1075  FlushBufferToFile();
1076  */
1077 
1078  break;
1079  }// case roNONE
1080 
1081  case roRMS :
1082  {
1083  #pragma omp parallel for if (BufferSize > MinGridpointsToSampleInParallel)
1084  for (size_t i = 0; i < BufferSize; i++)
1085  {
1086  StoreBuffer[i] += (SourceData[i] * SourceData[i]);
1087  }
1088  break;
1089  }// case roRMS
1090 
1091  case roMAX :
1092  {
1093  #pragma omp parallel for if (BufferSize > MinGridpointsToSampleInParallel)
1094  for (size_t i = 0; i < BufferSize; i++)
1095  {
1096  if (StoreBuffer[i] < SourceData[i]) StoreBuffer[i] = SourceData[i];
1097  }
1098  break;
1099  }//case roMAX
1100 
1101  case roMIN :
1102  {
1103  #pragma omp parallel for if (BufferSize > MinGridpointsToSampleInParallel)
1104  for (size_t i = 0; i < BufferSize; i++)
1105  {
1106  if (StoreBuffer[i] > SourceData[i]) StoreBuffer[i] = SourceData[i];
1107  }
1108  break;
1109  } //case roMIN
1110  }// switch
1111 }// end of Sample
1112 //------------------------------------------------------------------------------
1113 
1114 
1115 /**
1116  * Apply post-processing on the buffer and flush it to the file.
1117  */
1119 {
1120  // run inherited method
1122  // When no reduction operator is applied, the data is flushed after every time step
1123  if (ReductionOp != roNONE) FlushBufferToFile();
1124 }// end of PostProcessing
1125 //------------------------------------------------------------------------------
1126 
1127 /**
1128  * Checkpoint the stream
1129  */
1131 {
1132  // raw data has already been flushed, others has to be flushed here.
1133  if (ReductionOp != roNONE) FlushBufferToFile();
1134 }// end of Checkpoint
1135 //------------------------------------------------------------------------------
1136 
1137 /**
1138  * Close stream (apply post-processing if necessary, flush data and close).
1139  */
1141 {
1142  // the dataset is still opened
1143  if (HDF5_DatasetId != H5I_BADID)
1144  {
1146  }
1147 
1148  HDF5_DatasetId = H5I_BADID;
1149 }// end of Close
1150 //------------------------------------------------------------------------------
1151 
1152 
1153 //----------------------------------------------------------------------------//
1154 // TWholeDomainOutputHDF5Stream implementation //
1155 // protected methods //
1156 //----------------------------------------------------------------------------//
1157 
1158 
1159 /**
1160  * Flush the buffer down to the file at the actual position.
1161  */
1163 {
1165  TDimensionSizes Position(0,0,0);
1166 
1167  // Not used for roNONE now!
1168  if (ReductionOp == roNONE)
1169  {
1170  Position.T = SampledTimeStep;
1171  Size.T = SampledTimeStep;
1172  }
1173 
1175  Position,
1176  Size,
1177  StoreBuffer);
1178  SampledTimeStep++;
1179 }// end of FlushToFile
1180 //------------------------------------------------------------------------------
1181 
1182 
size_t Z
Z dimension size.
virtual float * GetRawData()
Get raw data out of the class (for direct kernel access).
size_t SampledTimeStep
Time step to store (N/A for aggregated).
size_t GetTotalNumberOfElementsInAllCuboids() const
Get the total number of elements to be sampled within all cuboids.
hid_t CreateGroup(const hid_t ParentGroup, const char *GroupName)
Create a HDF5 group at a specified place in the file tree.
Definition: HDF5_File.cpp:201
virtual void FlushBufferToFile()
Flush the buffer to the file.
std::vector< TCuboidInfo > CuboidsInfo
vector keeping handles and positions of all cuboids
TReductionOperator
How to aggregate data.
TCuboidOutputHDF5Stream(THDF5_File &HDF5_File, const char *HDF5_GroupName, const TRealMatrix &SourceMatrix, const TIndexMatrix &SensorMask, const TReductionOperator ReductionOp, float *BufferToReuse=NULL)
Constructor - links the HDF5 File, SourceMatrix, and SensorMask together.
size_t GetStartTimeIndex() const
Get start time index for sensor recording.
Definition: Parameters.h:215
char * HDF5_RootObjectName
Dataset name.
virtual void Reopen()
Reopen the output stream after restart and reload data.
virtual size_t GetTotalElementCount() const
Get element count of the matrix.
const TReductionOperator ReductionOp
Reduction operator.
hid_t OpenGroup(const hid_t ParentGroup, const char *GroupName)
Open a HDF5 group at a specified place in the file tree.
Definition: HDF5_File.cpp:229
const TIndexMatrix & SensorMask
Sensor mask to sample data.
TDimensionSizes GetBottomRightCorner(const size_t &index) const
Get the bottom right corner of the index-th cuboid.
Definition: IndexMatrix.h:116
bool BufferReuse
if true, the container reuses e.g. Temp_1_RS3D, Temp_2_RS3D, Temp_3_RS3D.
virtual void Close()
Close stream (apply post-processing if necessary, flush data and close).
void WriteCuboidToHyperSlab(const hid_t HDF5_Dataset_id, const TDimensionSizes &HyperslabPosition, const TDimensionSizes &CuboidPosition, const TDimensionSizes &CuboidSize, const TDimensionSizes &MatrixDimensions, const float *MatrixData)
Write a cuboid selected inside MatrixData into a Hyperslab.
Definition: HDF5_File.cpp:633
virtual size_t GetTotalElementCount() const
Get total element count of the matrix.
virtual size_t * GetRawData()
Get raw data out of the class (for direct kernel access).
TIndexOutputHDF5Stream(THDF5_File &HDF5_File, const char *HDF5_ObjectName, const TRealMatrix &SourceMatrix, const TIndexMatrix &SensorMask, const TReductionOperator ReductionOp, float *BufferToReuse=NULL)
Constructor - links the HDF5 dataset, SourceMatrix, and SensorMask together.
virtual void Sample()
Sample data into buffer and apply reduction, or flush to disk (no sensor mask here).
size_t X
X dimension size.
virtual void Reopen()
Reopen the output stream after restart and reload data.
virtual void Sample()
Sample data into buffer, apply reduction or flush to disk - based on a sensor mask.
The header file containing the parameters of the simulation.
const TIndexMatrix & SensorMask
Sensor mask to sample data.
virtual void PostProcess()
Apply post-processing on the buffer and flush it to the file.
hid_t HDF5_CuboidId
ID of the dataset storing the given cuboid.
void WriteHyperSlab(const hid_t HDF5_Dataset_id, const TDimensionSizes &Position, const TDimensionSizes &Size, const float *Data)
Write a hyper-slab into the dataset - float dataset.
Definition: HDF5_File.cpp:467
virtual void AllocateMemory()
A generic function to allocate memory - not used in the base class.
size_t SampledTimeStep
Timestep to store (N/A for aggregated).
virtual TDimensionSizes GetDimensionSizes() const
Get dimension sizes of the matrix.
float * StoreBuffer
Temporary buffer for store - only if Buffer Reuse = false!
size_t Get_t_index() const
Get simulation time step.
Definition: Parameters.h:91
const TRealMatrix & SourceMatrix
Source matrix to be sampled.
virtual void Checkpoint()
Checkpoint the stream.
virtual void FlushBufferToFile()
Flush the buffer to the file.
virtual ~TWholeDomainOutputHDF5Stream()
Destructor.
void WriteMatrixDataType(const hid_t ParentGroup, const char *DatasetName, const THDF5_MatrixDataType &MatrixDataType)
Write matrix data type into the dataset under a specified group.
Definition: HDF5_File.cpp:1116
The header file of classes responsible for storing output quantities into the output HDF5 file...
void WriteMatrixDomainType(const hid_t ParentGroup, const char *DatasetName, const THDF5_MatrixDomainType &MatrixDomainType)
Write matrix domain type into the dataset under the root group.
Definition: HDF5_File.cpp:1135
Class storing all parameters of the simulation.
Definition: Parameters.h:51
TDimensionSizes GetTopLeftCorner(const size_t &index) const
Get the top left corner of the index-th cuboid.
Definition: IndexMatrix.h:99
virtual void PostProcess()
Apply post-processing on the buffer and flush it to the file.
hid_t GetRootGroup() const
Get handle to the root group.
Definition: HDF5_File.h:581
virtual void Create()
Create a HDF5 stream and allocate data for it.
The header file containing all error messages of the project.
hid_t CreateFloatDataset(const hid_t ParentGroup, const char *DatasetName, const TDimensionSizes &DimensionSizes, const TDimensionSizes &ChunkSizes, const size_t CompressionLevel)
Create the HDF5 dataset at a specified place in the file tree (3D/4D).
Definition: HDF5_File.cpp:291
size_t GetElementCount() const
Get element count, in 3D only spatial domain, in 4D with time.
hid_t OpenDataset(const hid_t ParentGroup, const char *DatasetName)
Open the HDF5 dataset at a specified place in the file tree.
Definition: HDF5_File.cpp:264
Abstract base class for output data streams (sampled data).
virtual void Checkpoint()
Checkpoint the stream and close.
virtual void Close()
Close stream (apply post-processing if necessary, flush data and close).
virtual void FreeMemory()
A generic function to free memory - not used in the base class.
The class for real matrices.
Definition: RealMatrix.h:48
size_t Y
Y dimension size.
static const size_t ChunkSize_4MB
chunk size of 4MB in number of float elements.
This structure information about a HDF5 dataset (one cuboid). Namely, its HDF5_ID, Starting position in a lineup buffer.
void ReadCompleteDataset(const hid_t ParentGroup, const char *DatasetName, const TDimensionSizes &DimensionSizes, float *Data)
Read data from the dataset under a specified group - float dataset.
Definition: HDF5_File.cpp:954
size_t Get_Nt() const
Get Nt value.
Definition: Parameters.h:89
virtual void Checkpoint()
Checkpoint the stream and close.
The class for 64b unsigned integers (indices). It is used for sensor_mask_index or sensor_corners_mas...
Definition: IndexMatrix.h:50
virtual void PostProcess()
Apply post-processing on the buffer and flush it to the file.
size_t T
Number of time steps (for time series datasets).
void CloseGroup(const hid_t Group)
Close HDF5 group.
Definition: HDF5_File.cpp:251
size_t SampledTimeStep
Time step to store (N/A for aggregated).
virtual void Sample()
Sample data into buffer and apply reduction, or flush to disk - based on a sensor mask...
virtual void Close()
Close stream (apply post-processing if necessary, flush data and close).
size_t GetCompressionLevel() const
Get compression level.
Definition: Parameters.h:208
size_t BufferSize
Buffer size.
size_t StartingPossitionInBuffer
Having a single buffer for all cuboids, where this one starts.
hid_t HDF5_GroupId
Handle to a HDF5 dataset.
struct TDimensionSizes GetDimensionSizes() const
Get dimension sizes of the matrix.
const int DATA_ALIGNMENT
memory alignment for SSE, SSE2, SSE3, SSE4 (16B)
hid_t HDF5_DatasetId
Handle to a HDF5 dataset.
virtual void Reopen()
Reopen the output stream after restart and reload data.
virtual hid_t CreateCuboidDataset(const size_t Index)
Create a new dataset for a given cuboid specified by index (order).
virtual void Create()
Create a HDF5 stream and allocate data for it.
hid_t HDF5_DatasetId
Handle to a HDF5 dataset.
const char *const Matrix_ERR_FMT_NotEnoughMemory
Matrix class error message.
Definition: ErrorMessages.h:81
void CloseDataset(const hid_t HDF5_Dataset_id)
Close the HDF5 dataset.
Definition: HDF5_File.cpp:451
virtual void PostProcess()
Apply post-processing on the buffer and flush it to the file.
virtual void FlushBufferToFile()
Flush the buffer to the file.
THDF5_File & HDF5_File
HDF5 file handle.
virtual ~TIndexOutputHDF5Stream()
Destructor.
TWholeDomainOutputHDF5Stream(THDF5_File &HDF5_File, const char *HDF5_DatasetName, const TRealMatrix &SourceMatrix, const TReductionOperator ReductionOp, float *BufferToReuse=NULL)
Constructor - links the HDF5 File, SourceMatrix, and SensorMask together.
Class wrapping the HDF5 routines.
Definition: HDF5_File.h:506
virtual void Create()
Create a HDF5 stream and allocate data for it.
Structure with 4D dimension sizes (3 in space and 1 in time).
virtual ~TCuboidOutputHDF5Stream()
Destructor.
static TParameters * GetInstance()
Get instance of the singleton class.
Definition: Parameters.cpp:74