Skip to content

Commit c692dc7

Browse files
committed
Support custom hierarchies with attributes
1 parent 8d48e2d commit c692dc7

File tree

4 files changed

+129
-3
lines changed

4 files changed

+129
-3
lines changed

include/openPMD/CustomHierarchy.hpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,31 @@
2020
*/
2121
#pragma once
2222

23+
#include "openPMD/IO/AbstractIOHandler.hpp"
2324
#include "openPMD/backend/Container.hpp"
2425

2526
#include <iostream>
27+
#include <set>
28+
#include <string>
2629
#include <type_traits>
2730

2831
namespace openPMD
2932
{
3033
class CustomHierarchy;
3134
namespace internal
3235
{
36+
struct MeshesParticlesPath
37+
{
38+
std::set<std::string> paths;
39+
[[nodiscard]] bool ignore(std::string const &name) const;
40+
};
3341
using CustomHierarchyData = ContainerData<CustomHierarchy>;
34-
}
42+
} // namespace internal
3543

3644
class CustomHierarchy : public Container<CustomHierarchy>
3745
{
3846
friend class Iteration;
47+
friend class Container<CustomHierarchy>;
3948

4049
private:
4150
using Container_t = Container<CustomHierarchy>;
@@ -51,6 +60,10 @@ class CustomHierarchy : public Container<CustomHierarchy>
5160
Container_t::setData(std::move(data));
5261
}
5362

63+
void read(internal::MeshesParticlesPath const &);
64+
65+
void flush(std::string const &path, internal::FlushParams const &) override;
66+
5467
public:
5568
CustomHierarchy(CustomHierarchy const &other) = default;
5669
CustomHierarchy(CustomHierarchy &&other) = default;

src/CustomHierarchy.cpp

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,65 @@
2020
*/
2121

2222
#include "openPMD/CustomHierarchy.hpp"
23+
#include "openPMD/IO/AbstractIOHandler.hpp"
24+
#include "openPMD/IO/Access.hpp"
25+
#include "openPMD/IO/IOTask.hpp"
26+
#include "openPMD/backend/Attributable.hpp"
2327

2428
namespace openPMD
2529
{
30+
namespace internal
31+
{
32+
bool MeshesParticlesPath::ignore(const std::string &name) const
33+
{
34+
return paths.find(name) != paths.end();
35+
}
36+
} // namespace internal
37+
2638
CustomHierarchy::CustomHierarchy() = default;
27-
CustomHierarchy::CustomHierarchy(NoInit): Container_t(NoInit()) {}
28-
}
39+
CustomHierarchy::CustomHierarchy(NoInit) : Container_t(NoInit())
40+
{}
41+
42+
void CustomHierarchy::read(internal::MeshesParticlesPath const &mpp)
43+
{
44+
/*
45+
* Convention for CustomHierarchy::flush and CustomHierarchy::read:
46+
* Path is created/opened already at entry point of method, method needs
47+
* to create/open path for contained subpaths.
48+
*/
49+
Attributable::readAttributes(ReadMode::FullyReread);
50+
Parameter<Operation::LIST_PATHS> pList;
51+
IOHandler()->enqueue(IOTask(this, pList));
52+
IOHandler()->flush(internal::defaultFlushParams);
53+
for (auto const &path : *pList.paths)
54+
{
55+
if (mpp.ignore(path))
56+
{
57+
continue;
58+
}
59+
Parameter<Operation::OPEN_PATH> pOpen;
60+
pOpen.path = path;
61+
auto subpath = this->operator[](path);
62+
IOHandler()->enqueue(IOTask(&subpath, pOpen));
63+
subpath.read(mpp);
64+
}
65+
}
66+
67+
void CustomHierarchy::flush(
68+
std::string const & /* path */, internal::FlushParams const &flushParams)
69+
{
70+
/*
71+
* Convention for CustomHierarchy::flush and CustomHierarchy::read:
72+
* Path is created/opened already at entry point of method, method needs
73+
* to create/open path for contained subpaths.
74+
*/
75+
Parameter<Operation::CREATE_PATH> pCreate;
76+
for (auto &[name, subpath] : *this)
77+
{
78+
pCreate.path = name;
79+
IOHandler()->enqueue(IOTask(this, pCreate));
80+
subpath.flush(name, flushParams);
81+
}
82+
flushAttributes(flushParams);
83+
}
84+
} // namespace openPMD

src/Iteration.cpp

Lines changed: 23 additions & 0 deletions
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/Iteration.hpp"
22+
#include "openPMD/CustomHierarchy.hpp"
2223
#include "openPMD/Dataset.hpp"
2324
#include "openPMD/Datatype.hpp"
2425
#include "openPMD/Series.hpp"
@@ -290,8 +291,12 @@ void Iteration::flushVariableBased(
290291
}
291292
}
292293

294+
/*
295+
* @todo move much of this logic to CustomHierarchy::flush
296+
*/
293297
void Iteration::flushIteration(internal::FlushParams const &flushParams)
294298
{
299+
CustomHierarchy::flush("", flushParams);
295300
if (access::readOnly(IOHandler()->m_frontendAccess))
296301
{
297302
for (auto &m : meshes)
@@ -388,6 +393,9 @@ void Iteration::readGorVBased(std::string const &groupPath, bool doBeginStep)
388393
read_impl(groupPath);
389394
}
390395

396+
/*
397+
* @todo move lots of this to CustomHierarchy::read
398+
*/
391399
void Iteration::read_impl(std::string const &groupPath)
392400
{
393401
Parameter<Operation::OPEN_PATH> pOpen;
@@ -484,6 +492,21 @@ void Iteration::read_impl(std::string const &groupPath)
484492
hasParticles = s.containsAttribute("particlesPath");
485493
}
486494

495+
{
496+
internal::MeshesParticlesPath mpp;
497+
if (hasMeshes)
498+
{
499+
mpp.paths.emplace(auxiliary::trim(
500+
s.meshesPath(), [](char const &c) { return c == '/'; }));
501+
}
502+
if (hasParticles)
503+
{
504+
mpp.paths.emplace(auxiliary::trim(
505+
s.particlesPath(), [](char const &c) { return c == '/'; }));
506+
}
507+
CustomHierarchy::read(mpp);
508+
}
509+
487510
if (hasMeshes)
488511
{
489512
try

test/CoreTest.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// expose private and protected members for invasive testing
22
#include "openPMD/Datatype.hpp"
33
#include "openPMD/Error.hpp"
4+
#include "openPMD/IO/Access.hpp"
45
#if openPMD_USE_INVASIVE_TESTS
56
#define OPENPMD_private public:
67
#define OPENPMD_protected public:
@@ -158,6 +159,39 @@ TEST_CASE("attribute_dtype_test", "[core]")
158159
}
159160
}
160161

162+
TEST_CASE("custom_hierarchies", "[core]")
163+
{
164+
std::string filePath = "../samples/custom_hierarchies.json";
165+
Series write(filePath, Access::CREATE);
166+
write.iterations[0];
167+
write.close();
168+
169+
Series read(filePath, Access::READ_ONLY);
170+
REQUIRE(read.iterations[0].size() == 0);
171+
read.close();
172+
173+
write = Series(filePath, Access::READ_WRITE);
174+
write.iterations[0]["custom"]["hierarchy"];
175+
write.iterations[0]["custom"].setAttribute("string", "attribute");
176+
write.iterations[0]["custom"]["hierarchy"].setAttribute("number", 3);
177+
write.iterations[0]["no_attributes"];
178+
write.close();
179+
180+
read = Series(filePath, Access::READ_ONLY);
181+
REQUIRE(read.iterations[0].size() == 2);
182+
REQUIRE(read.iterations[0].count("custom") == 1);
183+
REQUIRE(read.iterations[0].count("no_attributes") == 1);
184+
REQUIRE(
185+
read.iterations[0]["custom"]
186+
.getAttribute("string")
187+
.get<std::string>() == "attribute");
188+
REQUIRE(
189+
read.iterations[0]["custom"]["hierarchy"]
190+
.getAttribute("number")
191+
.get<int>() == 3);
192+
read.close();
193+
}
194+
161195
TEST_CASE("myPath", "[core]")
162196
{
163197
#if openPMD_USE_INVASIVE_TESTS

0 commit comments

Comments
 (0)