Skip to content

Commit 605bd55

Browse files
committed
Init meshes/particles synchronously from the start
1 parent bfde8c5 commit 605bd55

File tree

3 files changed

+132
-55
lines changed

3 files changed

+132
-55
lines changed

include/openPMD/CustomHierarchy.hpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ namespace internal
7272
{
7373
explicit CustomHierarchyData();
7474

75+
void syncAttributables();
76+
7577
Container<RecordComponent> m_embeddedDatasets;
7678
Container<Mesh> m_embeddedMeshes;
7779
Container<ParticleSpecies> m_embeddedParticles;
@@ -113,10 +115,6 @@ class CustomHierarchy : public Container<CustomHierarchy>
113115
internal::MeshesParticlesPath &,
114116
std::vector<std::string> currentPath);
115117

116-
template <typename T>
117-
static void
118-
synchronizeContainers(Container<T> &target, Container<T> &source);
119-
120118
protected:
121119
CustomHierarchy();
122120
CustomHierarchy(NoInit);
@@ -153,12 +151,19 @@ class CustomHierarchy : public Container<CustomHierarchy>
153151
CustomHierarchy &operator=(CustomHierarchy const &) = default;
154152
CustomHierarchy &operator=(CustomHierarchy &&) = default;
155153

154+
mapped_type &operator[](key_type &&key);
155+
mapped_type &operator[](key_type const &key);
156+
156157
Container<RecordComponent> &datasets();
157158

158159
template <typename ContainedType>
159160
auto asContainerOf() -> Container<ContainedType> &;
160161

161162
Container<Mesh> meshes{};
162163
Container<ParticleSpecies> particles{};
164+
165+
private:
166+
template <typename KeyType>
167+
mapped_type &bracketOperatorImpl(KeyType &&);
163168
};
164169
} // namespace openPMD

include/openPMD/backend/Attributable.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,17 @@ namespace internal
115115
AttributableData(AttributableData &&) = delete;
116116
virtual ~AttributableData() = default;
117117

118+
inline std::shared_ptr<SharedAttributableData> &
119+
asSharedPtrOfAttributable()
120+
{
121+
return *this;
122+
}
123+
inline std::shared_ptr<SharedAttributableData> const &
124+
asSharedPtrOfAttributable() const
125+
{
126+
return *this;
127+
}
128+
118129
AttributableData &operator=(AttributableData const &) = delete;
119130
AttributableData &operator=(AttributableData &&) = delete;
120131
};

src/CustomHierarchy.cpp

Lines changed: 112 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
*/
2121

2222
#include "openPMD/CustomHierarchy.hpp"
23+
#include "openPMD/Error.hpp"
2324
#include "openPMD/IO/AbstractIOHandler.hpp"
2425
#include "openPMD/IO/Access.hpp"
2526
#include "openPMD/IO/IOTask.hpp"
@@ -34,6 +35,7 @@
3435
#include <initializer_list>
3536
#include <iterator>
3637
#include <memory>
38+
#include <optional>
3739
#include <regex>
3840
#include <sstream>
3941

@@ -142,6 +144,11 @@ namespace internal
142144
}
143145

144146
CustomHierarchyData::CustomHierarchyData()
147+
{
148+
syncAttributables();
149+
}
150+
151+
void CustomHierarchyData::syncAttributables()
145152
{
146153
/*
147154
* m_embeddeddatasets and its friends should point to the same instance
@@ -150,10 +157,8 @@ namespace internal
150157
for (auto p : std::initializer_list<Attributable *>{
151158
&m_embeddedDatasets, &m_embeddedMeshes, &m_embeddedParticles})
152159
{
153-
static_cast<std::shared_ptr<internal::SharedAttributableData> &>(
154-
*p->m_attri) =
155-
static_cast<
156-
std::shared_ptr<internal::SharedAttributableData> &>(*this);
160+
p->m_attri->asSharedPtrOfAttributable() =
161+
this->asSharedPtrOfAttributable();
157162
}
158163
}
159164
} // namespace internal
@@ -310,20 +315,6 @@ void CustomHierarchy::read(
310315
constantComponentsPushback.push_back(path);
311316
container().erase(path);
312317
}
313-
else
314-
{
315-
if (path == defaultMeshesPath)
316-
{
317-
synchronizeContainers(
318-
subpath.get().m_embeddedMeshes, meshes);
319-
}
320-
// no else, they might be the same
321-
if (path == defaultParticlesPath)
322-
{
323-
synchronizeContainers(
324-
subpath.get().m_embeddedParticles, particles);
325-
}
326-
}
327318
break;
328319
}
329320
case internal::ContainedType::Mesh: {
@@ -401,33 +392,6 @@ void CustomHierarchy::read(
401392
}
402393
}
403394

404-
template <typename T>
405-
void CustomHierarchy::synchronizeContainers(
406-
Container<T> &target, Container<T> &source)
407-
{
408-
if (target.m_containerData.get() == source.m_containerData.get())
409-
{
410-
return;
411-
}
412-
auto &target_container = target.container();
413-
for (auto &pair : source.container())
414-
{
415-
pair.second.linkHierarchy(target.writable());
416-
target_container.emplace(std::move(pair));
417-
}
418-
source.container().clear();
419-
auto &target_attributes = target.get().m_attributes;
420-
for (auto &pair : source.get().m_attributes)
421-
{
422-
target_attributes.emplace(std::move(pair));
423-
}
424-
source.get().m_attributes.clear();
425-
source.setData(target.m_containerData);
426-
// We need to do this since we redirect the Attributable pointers for some
427-
// members:
428-
source.Attributable::setData(target.m_attri);
429-
}
430-
431395
void CustomHierarchy::flush_internal(
432396
internal::FlushParams const &flushParams,
433397
internal::MeshesParticlesPath &mpp,
@@ -445,16 +409,12 @@ void CustomHierarchy::flush_internal(
445409
{
446410
if (!meshes.empty())
447411
{
448-
auto &defaultMeshes =
449-
(*this)[defaultMeshesPath].asContainerOf<Mesh>();
450-
synchronizeContainers(defaultMeshes, meshes);
412+
(*this)[defaultMeshesPath];
451413
}
452414

453415
if (!particles.empty())
454416
{
455-
auto &defaultParticles =
456-
(*this)[defaultParticlesPath].asContainerOf<ParticleSpecies>();
457-
synchronizeContainers(defaultParticles, particles);
417+
(*this)[defaultParticlesPath];
458418
}
459419

460420
flushAttributes(flushParams);
@@ -585,6 +545,16 @@ bool CustomHierarchy::dirtyRecursive() const
585545
return false;
586546
}
587547

548+
auto CustomHierarchy::operator[](key_type &&key) -> mapped_type &
549+
{
550+
return bracketOperatorImpl(std::move(key));
551+
}
552+
553+
auto CustomHierarchy::operator[](key_type const &key) -> mapped_type &
554+
{
555+
return bracketOperatorImpl(key);
556+
}
557+
588558
Container<RecordComponent> &CustomHierarchy::datasets()
589559
{
590560
return get().m_embeddedDatasets;
@@ -626,4 +596,95 @@ template auto CustomHierarchy::asContainerOf<RecordComponent>()
626596
template auto CustomHierarchy::asContainerOf<Mesh>() -> Container<Mesh> &;
627597
template auto CustomHierarchy::asContainerOf<ParticleSpecies>()
628598
-> Container<ParticleSpecies> &;
599+
600+
template <typename KeyType>
601+
auto CustomHierarchy::bracketOperatorImpl(KeyType &&provided_key)
602+
-> mapped_type &
603+
{
604+
auto &cont = container();
605+
auto find_special_key =
606+
[&cont, &provided_key, this](
607+
char const *special_key,
608+
auto &alias,
609+
auto &&embeddedAccessor) -> std::optional<mapped_type *> {
610+
if (provided_key == special_key)
611+
{
612+
if (auto it = cont.find(provided_key); it != cont.end())
613+
{
614+
if (it->second.m_attri->get() != alias.m_attri->get() ||
615+
embeddedAccessor(it->second)->m_containerData.get() !=
616+
alias.m_containerData.get())
617+
{
618+
/*
619+
* This might happen if a user first creates a custom group
620+
* "fields" and sets the default meshes path as "fields"
621+
* only later.
622+
* If the CustomHierarchy::meshes alias carries no data yet,
623+
* we can just redirect it to that group now.
624+
* Otherwise, we need to fail.
625+
*/
626+
if (alias.empty() && alias.attributes().empty())
627+
{
628+
alias.m_containerData =
629+
embeddedAccessor(it->second)->m_containerData;
630+
alias.m_attri->asSharedPtrOfAttributable() =
631+
it->second.m_attri->asSharedPtrOfAttributable();
632+
return &it->second;
633+
}
634+
throw error::WrongAPIUsage(
635+
"Found a group '" + provided_key + "' at path '" +
636+
myPath().printGroup() +
637+
"' which is not synchronous with mesh/particles alias "
638+
"despite '" +
639+
special_key +
640+
"' being the default meshes/particles path. This can "
641+
"have happened because setting default "
642+
"meshes/particles path too late (after first flush). "
643+
"If that's not the case, this is likely an internal "
644+
"bug.");
645+
}
646+
return &it->second;
647+
}
648+
else
649+
{
650+
auto *res =
651+
&Container::operator[](std::forward<KeyType>(provided_key));
652+
embeddedAccessor(*res)->m_containerData = alias.m_containerData;
653+
res->m_attri->asSharedPtrOfAttributable() =
654+
alias.m_attri->asSharedPtrOfAttributable();
655+
res->m_customHierarchyData->syncAttributables();
656+
return res;
657+
}
658+
}
659+
else
660+
{
661+
return std::nullopt;
662+
}
663+
};
664+
if (auto res = find_special_key(
665+
defaultMeshesPath,
666+
meshes,
667+
[](auto &group) {
668+
return &group.m_customHierarchyData->m_embeddedMeshes;
669+
});
670+
res.has_value())
671+
{
672+
return **res;
673+
}
674+
if (auto res = find_special_key(
675+
defaultParticlesPath,
676+
particles,
677+
[](auto &group) {
678+
return &group.m_customHierarchyData->m_embeddedParticles;
679+
});
680+
res.has_value())
681+
{
682+
return **res;
683+
}
684+
else
685+
{
686+
return (*this).Container::operator[](
687+
std::forward<KeyType>(provided_key));
688+
}
689+
}
629690
} // namespace openPMD

0 commit comments

Comments
 (0)