Skip to content

Commit f9b4da9

Browse files
committed
Make shape an optional attribute for constant components
1 parent ff52a8d commit f9b4da9

File tree

4 files changed

+96
-32
lines changed

4 files changed

+96
-32
lines changed

include/openPMD/backend/Attributable.hpp

Lines changed: 29 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/IO/AbstractIOHandler.hpp"
2425
#include "openPMD/ThrowError.hpp"
2526
#include "openPMD/auxiliary/OutOfRangeMsg.hpp"
@@ -30,6 +31,7 @@
3031
#include <exception>
3132
#include <map>
3233
#include <memory>
34+
#include <optional>
3335
#include <string>
3436
#include <type_traits>
3537
#include <vector>
@@ -106,6 +108,7 @@ namespace internal
106108
friend class openPMD::Attributable;
107109

108110
using SharedData_t = std::shared_ptr<SharedAttributableData>;
111+
using A_MAP = SharedData_t::element_type::A_MAP;
109112

110113
public:
111114
AttributableData();
@@ -152,6 +155,32 @@ namespace internal
152155
std::shared_ptr<typename T::Data_t>(self, [](auto const *) {}));
153156
return res;
154157
}
158+
159+
inline auto attributes() -> A_MAP &
160+
{
161+
return operator*().m_attributes;
162+
}
163+
[[nodiscard]] inline auto attributes() const -> A_MAP const &
164+
{
165+
return operator*().m_attributes;
166+
}
167+
[[nodiscard]] inline auto
168+
readAttribute(std::string const &name) const -> Attribute const &
169+
{
170+
auto const & attr = attributes();
171+
if (auto it = attr.find(name); it != attr.end())
172+
{
173+
return it->second;
174+
}
175+
else
176+
{
177+
throw error::ReadError(
178+
error::AffectedObject::Attribute,
179+
error::Reason::NotFound,
180+
std::nullopt,
181+
"Not found: '" + name + "'.");
182+
}
183+
}
155184
};
156185

157186
template <typename, typename>

src/Iteration.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -641,8 +641,7 @@ void Iteration::readMeshes(std::string const &meshesPath)
641641
auto att_begin = aList.attributes->begin();
642642
auto att_end = aList.attributes->end();
643643
auto value = std::find(att_begin, att_end, "value");
644-
auto shape = std::find(att_begin, att_end, "shape");
645-
if (value != att_end && shape != att_end)
644+
if (value != att_end)
646645
{
647646
MeshRecordComponent &mrc = m;
648647
IOHandler()->enqueue(IOTask(&mrc, pOpen));

src/ParticleSpecies.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,7 @@ void ParticleSpecies::read()
7676
auto att_begin = aList.attributes->begin();
7777
auto att_end = aList.attributes->end();
7878
auto value = std::find(att_begin, att_end, "value");
79-
auto shape = std::find(att_begin, att_end, "shape");
80-
if (value != att_end && shape != att_end)
79+
if (value != att_end)
8180
{
8281
RecordComponent &rc = r;
8382
IOHandler()->enqueue(IOTask(&rc, pOpen));

src/RecordComponent.cpp

Lines changed: 65 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,14 @@ RecordComponent &RecordComponent::resetDataset(Dataset d)
108108
throw std::runtime_error("Dataset extent must be at least 1D.");
109109
if (d.empty())
110110
{
111-
if (d.dtype != Datatype::UNDEFINED)
111+
if (d.extent.empty())
112+
{
113+
throw error::Internal(
114+
"A zero-dimensional dataset is not to be considered empty, but "
115+
"undefined. This is an internal safeguard against future "
116+
"changes that might not consider this.");
117+
}
118+
else if (d.dtype != Datatype::UNDEFINED)
112119
{
113120
return makeEmpty(std::move(d));
114121
}
@@ -280,6 +287,13 @@ void RecordComponent::flush(
280287
{
281288
setUnitSI(1);
282289
}
290+
auto constant_component_write_shape = [&]() {
291+
auto extent = getExtent();
292+
return !extent.empty() &&
293+
std::none_of(extent.begin(), extent.end(), [](auto val) {
294+
return val == Dataset::JOINED_DIMENSION;
295+
});
296+
};
283297
if (!written())
284298
{
285299
if (constant())
@@ -299,16 +313,20 @@ void RecordComponent::flush(
299313
Operation::WRITE_ATT>::ChangesOverSteps::IfPossible;
300314
}
301315
IOHandler()->enqueue(IOTask(this, aWrite));
302-
aWrite.name = "shape";
303-
Attribute a(getExtent());
304-
aWrite.dtype = a.dtype;
305-
aWrite.resource = a.getResource();
306-
if (isVBased)
316+
if (constant_component_write_shape())
307317
{
308-
aWrite.changesOverSteps = Parameter<
309-
Operation::WRITE_ATT>::ChangesOverSteps::IfPossible;
318+
319+
aWrite.name = "shape";
320+
Attribute a(getExtent());
321+
aWrite.dtype = a.dtype;
322+
aWrite.resource = a.getResource();
323+
if (isVBased)
324+
{
325+
aWrite.changesOverSteps = Parameter<
326+
Operation::WRITE_ATT>::ChangesOverSteps::IfPossible;
327+
}
328+
IOHandler()->enqueue(IOTask(this, aWrite));
310329
}
311-
IOHandler()->enqueue(IOTask(this, aWrite));
312330
}
313331
else
314332
{
@@ -326,6 +344,13 @@ void RecordComponent::flush(
326344
{
327345
if (constant())
328346
{
347+
if (!constant_component_write_shape())
348+
{
349+
throw error::WrongAPIUsage(
350+
"Extended constant component from a previous shape to "
351+
"one that cannot be written (empty or with joined "
352+
"dimension).");
353+
}
329354
bool isVBased = retrieveSeries().iterationEncoding() ==
330355
IterationEncoding::variableBased;
331356
Parameter<Operation::WRITE_ATT> aWrite;
@@ -390,28 +415,35 @@ namespace
390415
};
391416
} // namespace
392417

418+
inline void breakpoint()
419+
{}
420+
393421
void RecordComponent::readBase(bool require_unit_si)
394422
{
395423
using DT = Datatype;
396-
// auto & rc = get();
397-
Parameter<Operation::READ_ATT> aRead;
424+
auto &rc = get();
398425

399-
if (constant() && !empty())
400-
{
401-
aRead.name = "value";
402-
IOHandler()->enqueue(IOTask(this, aRead));
403-
IOHandler()->flush(internal::defaultFlushParams);
426+
readAttributes(ReadMode::FullyReread);
404427

405-
Attribute a(*aRead.resource);
406-
DT dtype = *aRead.dtype;
428+
auto read_constant =
429+
[&]() // comment for forcing clang-format into putting a newline here
430+
{
431+
Attribute a = rc.readAttribute("value");
432+
DT dtype = a.dtype;
407433
setWritten(false, Attributable::EnqueueAsynchronously::No);
408434
switchNonVectorType<MakeConstant>(dtype, *this, a);
409435
setWritten(true, Attributable::EnqueueAsynchronously::No);
410436

411-
aRead.name = "shape";
412-
IOHandler()->enqueue(IOTask(this, aRead));
413-
IOHandler()->flush(internal::defaultFlushParams);
414-
a = Attribute(*aRead.resource);
437+
if (!containsAttribute("shape"))
438+
{
439+
setWritten(false, Attributable::EnqueueAsynchronously::No);
440+
resetDataset(Dataset(dtype, {}));
441+
setWritten(true, Attributable::EnqueueAsynchronously::No);
442+
443+
return;
444+
}
445+
446+
a = rc.attributes().at("shape");
415447
Extent e;
416448

417449
// uint64_t check
@@ -421,7 +453,7 @@ void RecordComponent::readBase(bool require_unit_si)
421453
else
422454
{
423455
std::ostringstream oss;
424-
oss << "Unexpected datatype (" << *aRead.dtype
456+
oss << "Unexpected datatype (" << a.dtype
425457
<< ") for attribute 'shape' (" << determineDatatype<uint64_t>()
426458
<< " aka uint64_t)";
427459
throw error::ReadError(
@@ -434,9 +466,13 @@ void RecordComponent::readBase(bool require_unit_si)
434466
setWritten(false, Attributable::EnqueueAsynchronously::No);
435467
resetDataset(Dataset(dtype, e));
436468
setWritten(true, Attributable::EnqueueAsynchronously::No);
437-
}
469+
};
438470

439-
readAttributes(ReadMode::FullyReread);
471+
if (constant() && !empty())
472+
{
473+
breakpoint();
474+
read_constant();
475+
}
440476

441477
if (require_unit_si)
442478
{
@@ -450,16 +486,17 @@ void RecordComponent::readBase(bool require_unit_si)
450486
"'" +
451487
myPath().openPMDPath() + "'.");
452488
}
453-
if (!getAttribute("unitSI").getOptional<double>().has_value())
489+
if (auto attr = getAttribute("unitSI");
490+
!attr.getOptional<double>().has_value())
454491
{
455492
throw error::ReadError(
456493
error::AffectedObject::Attribute,
457494
error::Reason::UnexpectedContent,
458495
{},
459496
"Unexpected Attribute datatype for 'unitSI' (expected double, "
460497
"found " +
461-
datatypeToString(Attribute(*aRead.resource).dtype) +
462-
") in '" + myPath().openPMDPath() + "'.");
498+
datatypeToString(attr.dtype) + ") in '" +
499+
myPath().openPMDPath() + "'.");
463500
}
464501
}
465502
}

0 commit comments

Comments
 (0)