Skip to content

Commit a6d18ab

Browse files
committed
Main implementation
Use magic number instead of API call (impl)
1 parent 578a73d commit a6d18ab

File tree

11 files changed

+205
-31
lines changed

11 files changed

+205
-31
lines changed

include/openPMD/Dataset.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222

2323
#include "openPMD/Datatype.hpp"
2424

25+
#include <limits>
2526
#include <memory>
27+
#include <optional>
2628
#include <string>
2729
#include <type_traits>
2830
#include <vector>
@@ -37,6 +39,11 @@ class Dataset
3739
friend class RecordComponent;
3840

3941
public:
42+
enum : std::uint64_t
43+
{
44+
JOINED_DIMENSION = std::numeric_limits<std::uint64_t>::max()
45+
};
46+
4047
Dataset(Datatype, Extent, std::string options = "{}");
4148

4249
/**
@@ -53,5 +60,9 @@ class Dataset
5360
Datatype dtype;
5461
uint8_t rank;
5562
std::string options = "{}"; //!< backend-dependent JSON configuration
63+
64+
bool empty() const;
65+
66+
std::optional<size_t> joinedDimension() const;
5667
};
5768
} // namespace openPMD

include/openPMD/IO/IOTask.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ struct OPENPMDAPI_EXPORT Parameter<Operation::CREATE_DATASET>
349349
Extent extent = {};
350350
Datatype dtype = Datatype::UNDEFINED;
351351
std::string options = "{}";
352+
std::optional<size_t> joinedDimension;
352353

353354
/** Warn about unused JSON paramters
354355
*

include/openPMD/RecordComponent.tpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,8 +257,17 @@ RecordComponent::storeChunk(T_ContiguousContainer &data, Offset o, Extent e)
257257
// default arguments
258258
// offset = {0u}: expand to right dim {0u, 0u, ...}
259259
Offset offset = o;
260-
if (o.size() == 1u && o.at(0) == 0u && dim > 1u)
261-
offset = Offset(dim, 0u);
260+
if (o.size() == 1u && o.at(0) == 0u)
261+
{
262+
if (joinedDimension().has_value())
263+
{
264+
offset.clear();
265+
}
266+
else if (dim > 1u)
267+
{
268+
offset = Offset(dim, 0u);
269+
}
270+
}
262271

263272
// extent = {-1u}: take full size
264273
Extent extent(dim, 1u);
@@ -301,6 +310,7 @@ RecordComponent::storeChunk(Offset o, Extent e, F &&createBuffer)
301310
dCreate.name = rc.m_name;
302311
dCreate.extent = getExtent();
303312
dCreate.dtype = getDatatype();
313+
dCreate.joinedDimension = joinedDimension();
304314
if (!rc.m_dataset.has_value())
305315
{
306316
throw error::WrongAPIUsage(

include/openPMD/backend/BaseRecordComponent.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ class BaseRecordComponent : public Attributable
8282
*/
8383
bool constant() const;
8484

85+
std::optional<size_t> joinedDimension() const;
86+
8587
/**
8688
* Get data chunks that are available to be loaded from the backend.
8789
* Note that this is backend-dependent information and the returned

include/openPMD/backend/PatchRecordComponent.hpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
*/
2121
#pragma once
2222

23+
#include "openPMD/Error.hpp"
2324
#include "openPMD/auxiliary/ShareRawInternal.hpp"
2425
#include "openPMD/backend/BaseRecordComponent.hpp"
2526

@@ -95,6 +96,9 @@ class PatchRecordComponent : public BaseRecordComponent
9596
template <typename T>
9697
void store(uint64_t idx, T);
9798

99+
template <typename T>
100+
void store(T);
101+
98102
// clang-format off
99103
OPENPMD_private
100104
// clang-format on
@@ -222,4 +226,33 @@ inline void PatchRecordComponent::store(uint64_t idx, T data)
222226
auto &rc = get();
223227
rc.m_chunks.push(IOTask(this, std::move(dWrite)));
224228
}
229+
230+
template <typename T>
231+
inline void PatchRecordComponent::store(T data)
232+
{
233+
Datatype dtype = determineDatatype<T>();
234+
if (dtype != getDatatype())
235+
{
236+
std::ostringstream oss;
237+
oss << "Datatypes of patch data (" << dtype << ") and dataset ("
238+
<< getDatatype() << ") do not match.";
239+
throw std::runtime_error(oss.str());
240+
}
241+
242+
if (!joinedDimension().has_value())
243+
{
244+
throw error::WrongAPIUsage(
245+
"[PatchRecordComponent::store] API call without explicit "
246+
"specification of index only allowed when a joined dimension is "
247+
"specified.");
248+
}
249+
250+
Parameter<Operation::WRITE_DATASET> dWrite;
251+
dWrite.offset = {};
252+
dWrite.extent = {1};
253+
dWrite.dtype = dtype;
254+
dWrite.data = std::make_shared<T>(data);
255+
auto &rc = get();
256+
rc.m_chunks.push(IOTask(this, std::move(dWrite)));
257+
}
225258
} // namespace openPMD

src/Dataset.cpp

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
* If not, see <http://www.gnu.org/licenses/>.
2020
*/
2121
#include "openPMD/Dataset.hpp"
22+
#include "openPMD/Error.hpp"
2223

2324
#include <cstddef>
2425
#include <iostream>
@@ -30,7 +31,11 @@ Dataset::Dataset(Datatype d, Extent e, std::string options_in)
3031
, dtype{d}
3132
, rank{static_cast<uint8_t>(e.size())}
3233
, options{std::move(options_in)}
33-
{}
34+
{
35+
// Call this in order to have early error message in case of wrong
36+
// specification of joined dimensions
37+
joinedDimension();
38+
}
3439

3540
Dataset::Dataset(Extent e) : Dataset(Datatype::UNDEFINED, std::move(e))
3641
{}
@@ -49,4 +54,41 @@ Dataset &Dataset::extend(Extent newExtents)
4954
extent = newExtents;
5055
return *this;
5156
}
57+
58+
bool Dataset::empty() const
59+
{
60+
auto jd = joinedDimension();
61+
for (size_t i = 0; i < extent.size(); ++i)
62+
{
63+
if (extent[i] == 0 && (!jd.has_value() || jd.value() != i))
64+
{
65+
return true;
66+
}
67+
}
68+
return false;
69+
}
70+
71+
std::optional<size_t> Dataset::joinedDimension() const
72+
{
73+
std::optional<size_t> res;
74+
for (size_t i = 0; i < extent.size(); ++i)
75+
{
76+
if (extent[i] == JOINED_DIMENSION)
77+
{
78+
if (res.has_value())
79+
{
80+
throw error::WrongAPIUsage(
81+
"Must specify JOINED_DIMENSION at most once (found at "
82+
"indices " +
83+
std::to_string(res.value()) + " and " + std::to_string(i) +
84+
")");
85+
}
86+
else
87+
{
88+
res = i;
89+
}
90+
}
91+
}
92+
return res;
93+
}
5294
} // namespace openPMD

src/IO/ADIOS/ADIOS2IOHandler.cpp

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,21 @@ namespace openPMD
6666

6767
#define HAS_ADIOS_2_8 (ADIOS2_VERSION_MAJOR * 100 + ADIOS2_VERSION_MINOR >= 208)
6868

69+
namespace
70+
{
71+
std::optional<size_t> joinedDimension(adios2::Dims const &dims)
72+
{
73+
for (size_t i = 0; i < dims.size(); ++i)
74+
{
75+
if (dims[i] == adios2::JoinedDim)
76+
{
77+
return i;
78+
}
79+
}
80+
return std::nullopt;
81+
}
82+
} // namespace
83+
6984
#if openPMD_HAVE_MPI
7085

7186
ADIOS2IOHandlerImpl::ADIOS2IOHandlerImpl(
@@ -641,8 +656,11 @@ void ADIOS2IOHandlerImpl::createDataset(
641656
varName + "' remain unused:\n");
642657

643658
// cast from openPMD::Extent to adios2::Dims
644-
adios2::Dims const shape(
645-
parameters.extent.begin(), parameters.extent.end());
659+
adios2::Dims shape(parameters.extent.begin(), parameters.extent.end());
660+
if (auto jd = parameters.joinedDimension; jd.has_value())
661+
{
662+
shape[jd.value()] = adios2::JoinedDim;
663+
}
646664

647665
auto &fileData = getFileData(file, IfFileNotOpen::ThrowError);
648666
switchAdios2VariableType<detail::VariableDefiner>(
@@ -1549,11 +1567,22 @@ adios2::Variable<T> ADIOS2IOHandlerImpl::verifyDataset(
15491567
std::to_string(requiredDim) + ", but has dimensionality " +
15501568
std::to_string(actualDim) + ")")
15511569
}
1570+
auto joinedDim = joinedDimension(shape);
15521571
for (unsigned int i = 0; i < actualDim; i++)
1572+
{
1573+
if (!joinedDim.has_value() || i != joinedDim.value())
1574+
{
1575+
VERIFY_ALWAYS(
1576+
offset[i] + extent[i] <= shape[i],
1577+
"[ADIOS2] Dataset access out of bounds.")
1578+
}
1579+
}
1580+
1581+
if (joinedDim.has_value())
15531582
{
15541583
VERIFY_ALWAYS(
1555-
offset[i] + extent[i] <= shape[i],
1556-
"[ADIOS2] Dataset access out of bounds.")
1584+
offset.empty(),
1585+
"[ADIOS2] Offset must be an empty vector in case of joined array.");
15571586
}
15581587

15591588
var.SetSelection(

src/RecordComponent.cpp

Lines changed: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,7 @@ RecordComponent &RecordComponent::resetDataset(Dataset d)
9595
}
9696
// if( d.extent.empty() )
9797
// throw std::runtime_error("Dataset extent must be at least 1D.");
98-
if (std::any_of(
99-
d.extent.begin(), d.extent.end(), [](Extent::value_type const &i) {
100-
return i == 0u;
101-
}))
98+
if (d.empty())
10299
return makeEmpty(std::move(d));
103100

104101
rc.m_isEmpty = false;
@@ -283,6 +280,7 @@ void RecordComponent::flush(
283280
dCreate.extent = getExtent();
284281
dCreate.dtype = getDatatype();
285282
dCreate.options = rc.m_dataset.value().options;
283+
dCreate.joinedDimension = joinedDimension();
286284
IOHandler()->enqueue(IOTask(this, dCreate));
287285
}
288286
}
@@ -451,21 +449,56 @@ void RecordComponent::verifyChunk(
451449
uint8_t dim = getDimensionality();
452450
Extent dse = getExtent();
453451

454-
if (e.size() != dim || o.size() != dim)
452+
if (auto jd = joinedDimension(); jd.has_value())
455453
{
456-
std::ostringstream oss;
457-
oss << "Dimensionality of chunk ("
458-
<< "offset=" << o.size() << "D, "
459-
<< "extent=" << e.size() << "D) "
460-
<< "and record component (" << int(dim) << "D) "
461-
<< "do not match.";
462-
throw std::runtime_error(oss.str());
454+
if (o.size() != 0)
455+
{
456+
std::ostringstream oss;
457+
oss << "Joined array: Must specify an empty offset (given: "
458+
<< "offset=" << o.size() << "D, "
459+
<< "extent=" << e.size() << "D).";
460+
throw std::runtime_error(oss.str());
461+
}
462+
if (e.size() != dim)
463+
{
464+
std::ostringstream oss;
465+
oss << "Joined array: Dimensionalities of chunk extent and dataset "
466+
"extent must be equivalent (given: "
467+
<< "offset=" << o.size() << "D, "
468+
<< "extent=" << e.size() << "D).";
469+
throw std::runtime_error(oss.str());
470+
}
471+
for (size_t i = 0; i < dim; ++i)
472+
{
473+
if (i != jd.value() && e[i] != dse[i])
474+
{
475+
throw std::runtime_error(
476+
"Joined array: Chunk extent on non-joined dimensions must "
477+
"be equivalent to dataset extents (Dimension on index " +
478+
std::to_string(i) + ". DS: " + std::to_string(dse[i]) +
479+
" - Chunk: " + std::to_string(o[i] + e[i]) + ")");
480+
}
481+
}
482+
}
483+
else
484+
{
485+
if (e.size() != dim || o.size() != dim)
486+
{
487+
std::ostringstream oss;
488+
oss << "Dimensionality of chunk ("
489+
<< "offset=" << o.size() << "D, "
490+
<< "extent=" << e.size() << "D) "
491+
<< "and record component (" << int(dim) << "D) "
492+
<< "do not match.";
493+
throw std::runtime_error(oss.str());
494+
}
495+
for (uint8_t i = 0; i < dim; ++i)
496+
if (dse[i] < o[i] + e[i])
497+
throw std::runtime_error(
498+
"Chunk does not reside inside dataset (Dimension on "
499+
"index " +
500+
std::to_string(i) + ". DS: " + std::to_string(dse[i]) +
501+
" - Chunk: " + std::to_string(o[i] + e[i]) + ")");
463502
}
464-
for (uint8_t i = 0; i < dim; ++i)
465-
if (dse[i] < o[i] + e[i])
466-
throw std::runtime_error(
467-
"Chunk does not reside inside dataset (Dimension on index " +
468-
std::to_string(i) + ". DS: " + std::to_string(dse[i]) +
469-
" - Chunk: " + std::to_string(o[i] + e[i]) + ")");
470503
}
471504
} // namespace openPMD

src/backend/BaseRecordComponent.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,19 @@ bool BaseRecordComponent::constant() const
6565
return get().m_isConstant;
6666
}
6767

68+
std::optional<size_t> BaseRecordComponent::joinedDimension() const
69+
{
70+
auto &rc = get();
71+
if (rc.m_dataset.has_value())
72+
{
73+
return rc.m_dataset.value().joinedDimension();
74+
}
75+
else
76+
{
77+
return false;
78+
}
79+
}
80+
6881
ChunkTable BaseRecordComponent::availableChunks()
6982
{
7083
auto &rc = get();

src/backend/PatchRecordComponent.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,7 @@ PatchRecordComponent &PatchRecordComponent::resetDataset(Dataset d)
4848
"written.");
4949
if (d.extent.empty())
5050
throw std::runtime_error("Dataset extent must be at least 1D.");
51-
if (std::any_of(
52-
d.extent.begin(), d.extent.end(), [](Extent::value_type const &i) {
53-
return i == 0u;
54-
}))
51+
if (d.empty())
5552
throw std::runtime_error(
5653
"Dataset extent must not be zero in any dimension.");
5754

@@ -128,6 +125,7 @@ void PatchRecordComponent::flush(
128125
dCreate.extent = getExtent();
129126
dCreate.dtype = getDatatype();
130127
dCreate.options = rc.m_dataset.value().options;
128+
dCreate.joinedDimension = joinedDimension();
131129
IOHandler()->enqueue(IOTask(this, dCreate));
132130
}
133131

0 commit comments

Comments
 (0)