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