/src/bag/api/bag_simplelayer.cpp
Line | Count | Source |
1 | | |
2 | | #include "bag_attributeinfo.h" |
3 | | #include "bag_private.h" |
4 | | #include "bag_simplelayer.h" |
5 | | #include "bag_simplelayerdescriptor.h" |
6 | | |
7 | | #include <algorithm> |
8 | | #include <array> |
9 | | #include <H5Cpp.h> |
10 | | |
11 | | |
12 | | namespace BAG { |
13 | | |
14 | | //! Constructor. |
15 | | /*! |
16 | | \param dataset |
17 | | The BAG Dataset this layer belongs to. |
18 | | \param descriptor |
19 | | The descriptor of this layer. |
20 | | \param pH5dataSet |
21 | | The HDF5 DataSet that stores this layer. |
22 | | */ |
23 | | SimpleLayer::SimpleLayer( |
24 | | Dataset& dataset, |
25 | | SimpleLayerDescriptor& descriptor, |
26 | | std::unique_ptr<::H5::DataSet, DeleteH5dataSet> pH5dataSet) |
27 | 120 | : Layer(dataset, descriptor) |
28 | 120 | , m_pH5dataSet(std::move(pH5dataSet)) |
29 | 120 | { |
30 | 120 | } |
31 | | |
32 | | //! Create a new simple layer. |
33 | | /*! |
34 | | \param dataset |
35 | | The BAG Dataset this layer belongs to. |
36 | | \param type |
37 | | The type of layer. |
38 | | \param chunkSize |
39 | | The chunk size the HDF5 DataSet will use. |
40 | | \param compressionLevel |
41 | | The compression level the HDF5 DataSet will use. |
42 | | |
43 | | \return |
44 | | The new simple layer. |
45 | | */ |
46 | | std::shared_ptr<SimpleLayer> SimpleLayer::create( |
47 | | Dataset& dataset, |
48 | | LayerType type, |
49 | | uint32_t rows, uint32_t cols, |
50 | | uint64_t chunkSize, |
51 | | int compressionLevel) |
52 | 0 | { |
53 | 0 | auto descriptor = SimpleLayerDescriptor::create(dataset, type, rows, cols, chunkSize, compressionLevel); |
54 | 0 | auto h5dataSet = SimpleLayer::createH5dataSet(dataset, *descriptor); |
55 | |
|
56 | 0 | return std::make_shared<SimpleLayer>(dataset, *descriptor, std::move(h5dataSet)); |
57 | 0 | } |
58 | | |
59 | | //! Open an existing simple layer. |
60 | | /*! |
61 | | \param dataset |
62 | | The BAG Dataset this layer belongs to. |
63 | | \param descriptor |
64 | | The descriptor of this layer. |
65 | | |
66 | | \return |
67 | | The specified simple layer. |
68 | | */ |
69 | | std::shared_ptr<SimpleLayer> SimpleLayer::open( |
70 | | Dataset& dataset, |
71 | | SimpleLayerDescriptor& descriptor) |
72 | 120 | { |
73 | 120 | const auto& h5file = dataset.getH5file(); |
74 | 120 | auto h5dataSet = std::unique_ptr<::H5::DataSet, DeleteH5dataSet>( |
75 | 120 | new ::H5::DataSet{h5file.openDataSet(descriptor.getInternalPath())}, |
76 | 120 | DeleteH5dataSet{}); |
77 | | |
78 | | // Configure the layer dimensions in the descriptor (we implicitally expect the layer |
79 | | // to be two-dimensional) |
80 | 120 | hsize_t dims[2]; |
81 | 120 | h5dataSet->getSpace().getSimpleExtentDims(dims); |
82 | 120 | descriptor.setDims(dims[0], dims[1]); |
83 | | |
84 | | // Read the min/max attribute values. |
85 | 120 | const auto possibleMinMax = dataset.getMinMax(descriptor.getLayerType()); |
86 | 120 | if (std::get<0>(possibleMinMax)) |
87 | 120 | descriptor.setMinMax(std::get<1>(possibleMinMax), |
88 | 120 | std::get<2>(possibleMinMax)); |
89 | | |
90 | 120 | return std::make_shared<SimpleLayer>(dataset, descriptor,std::move(h5dataSet)); |
91 | 120 | } |
92 | | |
93 | | |
94 | | //! Create the HDF5 DataSet. |
95 | | /*! |
96 | | \param dataset |
97 | | The BAG Dataset this layer belongs to. |
98 | | \param descriptor |
99 | | The descriptor of this layer. |
100 | | |
101 | | \return |
102 | | The new HDF5 DataSet. |
103 | | */ |
104 | | std::unique_ptr<::H5::DataSet, DeleteH5dataSet> |
105 | | SimpleLayer::createH5dataSet( |
106 | | const Dataset& dataset, |
107 | | const SimpleLayerDescriptor& descriptor) |
108 | 0 | { |
109 | 0 | uint32_t dim0 = 0, dim1 = 0; |
110 | 0 | std::tie(dim0, dim1) = descriptor.getDims(); |
111 | 0 | const std::array<hsize_t, kRank> fileDims{dim0, dim1}; |
112 | |
|
113 | 0 | ::H5::DataSpace h5dataSpace{kRank, fileDims.data(), fileDims.data()}; |
114 | |
|
115 | 0 | ::H5::FloatType h5dataType; |
116 | 0 | h5dataType.copy(::H5::PredType::NATIVE_FLOAT); |
117 | 0 | h5dataType.setOrder(H5T_ORDER_LE); |
118 | | |
119 | | // Create the creation property list. |
120 | 0 | const ::H5::DSetCreatPropList h5createPropList{}; |
121 | 0 | h5createPropList.setFillTime(H5D_FILL_TIME_ALLOC); |
122 | |
|
123 | 0 | constexpr float kFillValue = BAG_NULL_ELEVATION; |
124 | 0 | h5createPropList.setFillValue(h5dataType, &kFillValue); |
125 | | |
126 | | // Use chunk size and compression level from the descriptor. |
127 | 0 | const auto compressionLevel = descriptor.getCompressionLevel(); |
128 | 0 | const auto chunkSize = descriptor.getChunkSize(); |
129 | 0 | if (chunkSize > 0) |
130 | 0 | { |
131 | 0 | const std::array<hsize_t, kRank> chunkDims{chunkSize, chunkSize}; |
132 | 0 | h5createPropList.setChunk(kRank, chunkDims.data()); |
133 | |
|
134 | 0 | if (compressionLevel > 0 && compressionLevel <= kMaxCompressionLevel) |
135 | 0 | h5createPropList.setDeflate(compressionLevel); |
136 | 0 | } |
137 | 0 | else if (compressionLevel > 0) |
138 | 0 | throw CompressionNeedsChunkingSet{}; |
139 | | |
140 | | // Create the DataSet using the above. |
141 | 0 | const auto& h5file = dataset.getH5file(); |
142 | |
|
143 | 0 | auto pH5dataSet = std::unique_ptr<::H5::DataSet, DeleteH5dataSet>( |
144 | 0 | new ::H5::DataSet{h5file.createDataSet(descriptor.getInternalPath(), |
145 | 0 | h5dataType, h5dataSpace, h5createPropList)}, |
146 | 0 | DeleteH5dataSet{}); |
147 | | |
148 | | // Create any attributes. |
149 | 0 | const auto attInfo = getAttributeInfo(descriptor.getLayerType()); |
150 | |
|
151 | 0 | const ::H5::DataSpace minElevDataSpace{}; |
152 | 0 | const auto minElevAtt = pH5dataSet->createAttribute(attInfo.minName, |
153 | 0 | attInfo.h5type, minElevDataSpace); |
154 | |
|
155 | 0 | const ::H5::DataSpace maxElevDataSpace{}; |
156 | 0 | const auto maxElevAtt = pH5dataSet->createAttribute(attInfo.maxName, |
157 | 0 | attInfo.h5type, maxElevDataSpace); |
158 | | |
159 | | // Set initial min/max values. |
160 | 0 | constexpr float minElev = std::numeric_limits<float>::max(); |
161 | 0 | minElevAtt.write(attInfo.h5type, &minElev); |
162 | |
|
163 | 0 | constexpr float maxElev = std::numeric_limits<float>::lowest(); |
164 | 0 | maxElevAtt.write(attInfo.h5type, &maxElev); |
165 | |
|
166 | 0 | return pH5dataSet; |
167 | 0 | } |
168 | | |
169 | | //! \copydoc Layer::read |
170 | | UInt8Array SimpleLayer::readProxy( |
171 | | uint32_t rowStart, |
172 | | uint32_t columnStart, |
173 | | uint32_t rowEnd, |
174 | | uint32_t columnEnd) const |
175 | 0 | { |
176 | | // Query the file for the specified rows and columns. |
177 | 0 | const auto h5fileDataSpace = m_pH5dataSet->getSpace(); |
178 | |
|
179 | 0 | const auto rows = (rowEnd - rowStart) + 1; |
180 | 0 | const auto columns = (columnEnd - columnStart) + 1; |
181 | 0 | const std::array<hsize_t, kRank> count{rows, columns}; |
182 | 0 | const std::array<hsize_t, kRank> offset{rowStart, columnStart}; |
183 | |
|
184 | 0 | h5fileDataSpace.selectHyperslab(H5S_SELECT_SET, count.data(), offset.data()); |
185 | | |
186 | | // Initialize the output buffer. |
187 | 0 | const auto bufferSize = this->getDescriptor()->getReadBufferSize(rows, |
188 | 0 | columns); |
189 | 0 | UInt8Array buffer{bufferSize}; |
190 | | |
191 | | // Prepare the memory space. |
192 | 0 | const ::H5::DataSpace h5memSpace{kRank, count.data(), count.data()}; |
193 | |
|
194 | 0 | m_pH5dataSet->read(buffer.data(), H5Dget_type(m_pH5dataSet->getId()), |
195 | 0 | h5memSpace, h5fileDataSpace); |
196 | |
|
197 | 0 | return buffer; |
198 | 0 | } |
199 | | |
200 | | //! \copydoc Layer::writeAttributes |
201 | | void SimpleLayer::writeAttributesProxy() const |
202 | 0 | { |
203 | 0 | auto pDescriptor = this->getDescriptor(); |
204 | 0 | const auto attInfo = getAttributeInfo(pDescriptor->getLayerType()); |
205 | | |
206 | | // Write any attributes, from the layer descriptor. |
207 | | // min value |
208 | 0 | const auto minMax = pDescriptor->getMinMax(); |
209 | |
|
210 | 0 | const auto minAtt = m_pH5dataSet->openAttribute(attInfo.minName); |
211 | 0 | minAtt.write(attInfo.h5type, &std::get<0>(minMax)); |
212 | | |
213 | | // max value |
214 | 0 | const auto maxAtt = m_pH5dataSet->openAttribute(attInfo.maxName); |
215 | 0 | maxAtt.write(attInfo.h5type, &std::get<1>(minMax)); |
216 | 0 | } |
217 | | |
218 | | //! \copydoc Layer::write |
219 | | void SimpleLayer::writeProxy( |
220 | | uint32_t rowStart, |
221 | | uint32_t columnStart, |
222 | | uint32_t rowEnd, |
223 | | uint32_t columnEnd, |
224 | | const uint8_t* buffer) |
225 | 0 | { |
226 | 0 | auto h5fileDataSpace = m_pH5dataSet->getSpace(); |
227 | | |
228 | | // Make sure the area being written to does not exceed the file dimensions. |
229 | 0 | std::array<hsize_t, kRank> fileDims{}; |
230 | 0 | h5fileDataSpace.getSimpleExtentDims(fileDims.data()); |
231 | |
|
232 | 0 | if ((rowEnd >= fileDims[0]) || (columnEnd >= fileDims[1])) |
233 | 0 | throw InvalidWriteSize{}; |
234 | | |
235 | 0 | const auto rows = (rowEnd - rowStart) + 1; |
236 | 0 | const auto columns = (columnEnd - columnStart) + 1; |
237 | 0 | const std::array<hsize_t, kRank> count{rows, columns}; |
238 | 0 | const std::array<hsize_t, kRank> offset{rowStart, columnStart}; |
239 | |
|
240 | 0 | h5fileDataSpace.selectHyperslab(H5S_SELECT_SET, count.data(), offset.data()); |
241 | | |
242 | | // Prepare the memory space. |
243 | 0 | const ::H5::DataSpace h5memDataSpace{kRank, count.data(), count.data()}; |
244 | |
|
245 | 0 | m_pH5dataSet->write(buffer, H5Dget_type(m_pH5dataSet->getId()), |
246 | 0 | h5memDataSpace, h5fileDataSpace); |
247 | | |
248 | | // Update min/max attributes |
249 | 0 | auto pDescriptor = this->getDescriptor(); |
250 | 0 | const auto attInfo = getAttributeInfo(pDescriptor->getLayerType()); |
251 | 0 | float min = 0.f, max = 0.f; |
252 | |
|
253 | 0 | if (attInfo.h5type == ::H5::PredType::NATIVE_FLOAT) |
254 | 0 | { |
255 | 0 | const auto* floatBuffer = reinterpret_cast<const float*>(buffer); |
256 | |
|
257 | 0 | const auto begin = floatBuffer; |
258 | 0 | const auto end = floatBuffer + rows * columns; |
259 | |
|
260 | 0 | const auto mm = std::minmax_element(begin, end); |
261 | 0 | min = *std::get<0>(mm); |
262 | 0 | max = *std::get<1>(mm); |
263 | 0 | } |
264 | 0 | else if (attInfo.h5type == ::H5::PredType::NATIVE_UINT32) |
265 | 0 | { |
266 | 0 | const auto* uint32Buffer = reinterpret_cast<const uint32_t*>(buffer); |
267 | |
|
268 | 0 | const auto begin = uint32Buffer; |
269 | 0 | const auto end = uint32Buffer + rows * columns; |
270 | |
|
271 | 0 | const auto mm = std::minmax_element(begin, end); |
272 | 0 | min = static_cast<float>(*std::get<0>(mm)); |
273 | 0 | max = static_cast<float>(*std::get<1>(mm)); |
274 | 0 | } |
275 | 0 | else |
276 | 0 | throw UnsupportedAttributeType{}; |
277 | | |
278 | 0 | const float currentMin = std::get<0>(pDescriptor->getMinMax()); |
279 | 0 | const float currentMax = std::get<1>(pDescriptor->getMinMax()); |
280 | |
|
281 | 0 | pDescriptor->setMinMax(std::min(currentMin, min), std::max(currentMax, max)); |
282 | 0 | } |
283 | | |
284 | | } //namespace BAG |
285 | | |