Skip to content

Commit 7d13bea

Browse files
committed
Make shape an optional attribute for constant components
1 parent 53c0512 commit 7d13bea

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
{
@@ -323,6 +341,13 @@ void RecordComponent::flush(
323341
{
324342
if (constant())
325343
{
344+
if (!constant_component_write_shape())
345+
{
346+
throw error::WrongAPIUsage(
347+
"Extended constant component from a previous shape to "
348+
"one that cannot be written (empty or with joined "
349+
"dimension).");
350+
}
326351
bool isVBased = retrieveSeries().iterationEncoding() ==
327352
IterationEncoding::variableBased;
328353
Parameter<Operation::WRITE_ATT> aWrite;
@@ -387,28 +412,35 @@ namespace
387412
};
388413
} // namespace
389414

415+
inline void breakpoint()
416+
{}
417+
390418
void RecordComponent::readBase(bool require_unit_si)
391419
{
392420
using DT = Datatype;
393-
// auto & rc = get();
394-
Parameter<Operation::READ_ATT> aRead;
421+
auto &rc = get();
395422

396-
if (constant() && !empty())
397-
{
398-
aRead.name = "value";
399-
IOHandler()->enqueue(IOTask(this, aRead));
400-
IOHandler()->flush(internal::defaultFlushParams);
423+
readAttributes(ReadMode::FullyReread);
401424

402-
Attribute a(*aRead.resource);
403-
DT dtype = *aRead.dtype;
425+
auto read_constant =
426+
[&]() // comment for forcing clang-format into putting a newline here
427+
{
428+
Attribute a = rc.readAttribute("value");
429+
DT dtype = a.dtype;
404430
setWritten(false, Attributable::EnqueueAsynchronously::No);
405431
switchNonVectorType<MakeConstant>(dtype, *this, a);
406432
setWritten(true, Attributable::EnqueueAsynchronously::No);
407433

408-
aRead.name = "shape";
409-
IOHandler()->enqueue(IOTask(this, aRead));
410-
IOHandler()->flush(internal::defaultFlushParams);
411-
a = Attribute(*aRead.resource);
434+
if (!containsAttribute("shape"))
435+
{
436+
setWritten(false, Attributable::EnqueueAsynchronously::No);
437+
resetDataset(Dataset(dtype, {}));
438+
setWritten(true, Attributable::EnqueueAsynchronously::No);
439+
440+
return;
441+
}
442+
443+
a = rc.attributes().at("shape");
412444
Extent e;
413445

414446
// uint64_t check
@@ -418,7 +450,7 @@ void RecordComponent::readBase(bool require_unit_si)
418450
else
419451
{
420452
std::ostringstream oss;
421-
oss << "Unexpected datatype (" << *aRead.dtype
453+
oss << "Unexpected datatype (" << a.dtype
422454
<< ") for attribute 'shape' (" << determineDatatype<uint64_t>()
423455
<< " aka uint64_t)";
424456
throw error::ReadError(
@@ -431,9 +463,13 @@ void RecordComponent::readBase(bool require_unit_si)
431463
setWritten(false, Attributable::EnqueueAsynchronously::No);
432464
resetDataset(Dataset(dtype, e));
433465
setWritten(true, Attributable::EnqueueAsynchronously::No);
434-
}
466+
};
435467

436-
readAttributes(ReadMode::FullyReread);
468+
if (constant() && !empty())
469+
{
470+
breakpoint();
471+
read_constant();
472+
}
437473

438474
if (require_unit_si)
439475
{
@@ -447,16 +483,17 @@ void RecordComponent::readBase(bool require_unit_si)
447483
"'" +
448484
myPath().openPMDPath() + "'.");
449485
}
450-
if (!getAttribute("unitSI").getOptional<double>().has_value())
486+
if (auto attr = getAttribute("unitSI");
487+
!attr.getOptional<double>().has_value())
451488
{
452489
throw error::ReadError(
453490
error::AffectedObject::Attribute,
454491
error::Reason::UnexpectedContent,
455492
{},
456493
"Unexpected Attribute datatype for 'unitSI' (expected double, "
457494
"found " +
458-
datatypeToString(Attribute(*aRead.resource).dtype) +
459-
") in '" + myPath().openPMDPath() + "'.");
495+
datatypeToString(attr.dtype) + ") in '" +
496+
myPath().openPMDPath() + "'.");
460497
}
461498
}
462499
}

0 commit comments

Comments
 (0)