2323#include " openPMD/IO/AbstractIOHandler.hpp"
2424#include " openPMD/IO/Access.hpp"
2525#include " openPMD/IO/IOTask.hpp"
26+ #include " openPMD/RecordComponent.hpp"
2627#include " openPMD/backend/Attributable.hpp"
2728
29+ #include < deque>
30+ #include < memory>
31+
2832namespace openPMD
2933{
3034namespace internal
@@ -33,9 +37,25 @@ namespace internal
3337 {
3438 return paths.find (name) != paths.end ();
3539 }
40+
41+ CustomHierarchyData::CustomHierarchyData ()
42+ {
43+ /*
44+ * m_embeddeddatasets should point to the same instance of Attributable
45+ * Can only use a non-owning pointer in here in order to avoid shared
46+ * pointer cycles.
47+ * When handing this object out to users, we create a copy that has a
48+ * proper owning pointer (see CustomHierarchy::datasets()).
49+ */
50+ m_embeddedDatasets.Attributable ::setData (
51+ std::shared_ptr<AttributableData>(this , [](auto const *) {}));
52+ }
3653} // namespace internal
3754
38- CustomHierarchy::CustomHierarchy () = default ;
55+ CustomHierarchy::CustomHierarchy ()
56+ {
57+ setData (std::make_shared<Data_t>());
58+ }
3959CustomHierarchy::CustomHierarchy (NoInit) : Container_t(NoInit())
4060{}
4161
@@ -49,7 +69,10 @@ void CustomHierarchy::read(internal::MeshesParticlesPath const &mpp)
4969 Attributable::readAttributes (ReadMode::FullyReread);
5070 Parameter<Operation::LIST_PATHS> pList;
5171 IOHandler ()->enqueue (IOTask (this , pList));
72+ Parameter<Operation::LIST_DATASETS> dList;
73+ IOHandler ()->enqueue (IOTask (this , dList));
5274 IOHandler ()->flush (internal::defaultFlushParams);
75+ std::deque<std::string> constantComponentsPushback;
5376 for (auto const &path : *pList.paths )
5477 {
5578 if (mpp.ignore (path))
@@ -61,6 +84,39 @@ void CustomHierarchy::read(internal::MeshesParticlesPath const &mpp)
6184 auto subpath = this ->operator [](path);
6285 IOHandler ()->enqueue (IOTask (&subpath, pOpen));
6386 subpath.read (mpp);
87+ if (subpath.size () == 0 && subpath.containsAttribute (" shape" ) &&
88+ subpath.containsAttribute (" value" ))
89+ {
90+ // This is not a group, but a constant record component
91+ // Writable::~Writable() will deal with removing this from the
92+ // backend again.
93+ std::cout << " IS CONSTANT COMPONENT: " << path << std::endl;
94+ constantComponentsPushback.push_back (path);
95+ container ().erase (path);
96+ }
97+ }
98+ auto &data = get ();
99+ for (auto const &path : *dList.datasets )
100+ {
101+ auto &rc = data.m_embeddedDatasets [path];
102+ Parameter<Operation::OPEN_DATASET> dOpen;
103+ dOpen.name = path;
104+ IOHandler ()->enqueue (IOTask (&rc, dOpen));
105+ IOHandler ()->flush (internal::defaultFlushParams);
106+ rc.written () = false ;
107+ rc.resetDataset (Dataset (*dOpen.dtype , *dOpen.extent ));
108+ rc.written () = true ;
109+ rc.read ();
110+ }
111+
112+ for (auto const &path : constantComponentsPushback)
113+ {
114+ auto &rc = data.m_embeddedDatasets [path];
115+ Parameter<Operation::OPEN_PATH> pOpen;
116+ pOpen.path = path;
117+ IOHandler ()->enqueue (IOTask (&rc, pOpen));
118+ rc.get ().m_isConstant = true ;
119+ rc.read ();
64120 }
65121}
66122
@@ -82,6 +138,17 @@ void CustomHierarchy::flush(
82138 }
83139 subpath.flush (name, flushParams);
84140 }
141+ for (auto &[name, dataset] : get ().m_embeddedDatasets )
142+ {
143+ dataset.flush (name, flushParams);
144+ }
85145 flushAttributes (flushParams);
86146}
147+
148+ Container<RecordComponent> CustomHierarchy::datasets ()
149+ {
150+ Container<RecordComponent> res = get ().m_embeddedDatasets ;
151+ res.Attributable ::setData (m_customHierarchyData);
152+ return res;
153+ }
87154} // namespace openPMD
0 commit comments