Skip to content

Commit d4e3d4d

Browse files
committed
Initialize Series attributes and datasets from template
1 parent 544923b commit d4e3d4d

File tree

6 files changed

+255
-2
lines changed

6 files changed

+255
-2
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,7 @@ set(CORE_SOURCE
460460
src/auxiliary/Date.cpp
461461
src/auxiliary/Filesystem.cpp
462462
src/auxiliary/JSON.cpp
463+
src/auxiliary/TemplateFile.cpp
463464
src/backend/Attributable.cpp
464465
src/backend/BaseRecordComponent.cpp
465466
src/backend/Container.cpp

include/openPMD/Iteration.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,15 @@ namespace internal
115115
* alone.
116116
*/
117117
std::optional<std::string> m_overrideFilebasedFilename{};
118+
119+
enum TernaryBool
120+
{
121+
Undefined,
122+
True,
123+
False
124+
};
125+
TernaryBool hasMeshes = TernaryBool::Undefined;
126+
TernaryBool hasParticles = TernaryBool::Undefined;
118127
};
119128
} // namespace internal
120129
/** @brief Logical compilation of data from one snapshot (e.g. a single
@@ -239,6 +248,9 @@ class Iteration : public Attributable
239248
Container<Mesh> meshes{};
240249
Container<ParticleSpecies> particles{}; // particleSpecies?
241250

251+
bool hasMeshes() const;
252+
bool hasParticles() const;
253+
242254
virtual ~Iteration() = default;
243255

244256
private:
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#pragma once
2+
3+
#include "openPMD/Series.hpp"
4+
5+
namespace openPMD::auxiliary
6+
{
7+
// @todo replace uint64_t with proper type after merging #1285
8+
Series &initializeFromTemplate(
9+
Series &initializeMe, Series const &fromTemplate, uint64_t iteration);
10+
} // namespace openPMD::auxiliary

src/Iteration.cpp

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,50 @@ namespace openPMD
3636
using internal::CloseStatus;
3737
using internal::DeferredParseAccess;
3838

39+
bool Iteration::hasMeshes() const
40+
{
41+
/*
42+
* Currently defined at the Series level, but might be defined at the
43+
* Iteration level in next standard iterations.
44+
* Hence an Iteration:: method.
45+
*/
46+
47+
switch (get().hasMeshes)
48+
{
49+
case internal::IterationData::TernaryBool::True:
50+
return true;
51+
case internal::IterationData::TernaryBool::False:
52+
return false;
53+
case internal::IterationData::TernaryBool::Undefined: {
54+
Series s = retrieveSeries();
55+
return !meshes.empty() || s.containsAttribute("meshesPath");
56+
};
57+
}
58+
throw std::runtime_error("Unreachable!");
59+
}
60+
61+
bool Iteration::hasParticles() const
62+
{
63+
/*
64+
* Currently defined at the Series level, but might be defined at the
65+
* Iteration level in next standard iterations.
66+
* Hence an Iteration:: method.
67+
*/
68+
69+
switch (get().hasParticles)
70+
{
71+
case internal::IterationData::TernaryBool::True:
72+
return true;
73+
case internal::IterationData::TernaryBool::False:
74+
return false;
75+
case internal::IterationData::TernaryBool::Undefined: {
76+
Series s = retrieveSeries();
77+
return !particles.empty() || s.containsAttribute("particlesPath");
78+
};
79+
}
80+
throw std::runtime_error("Unreachable!");
81+
}
82+
3983
Iteration::Iteration() : Attributable{nullptr}
4084
{
4185
Attributable::setData(m_iterationData);
@@ -318,7 +362,7 @@ void Iteration::flush(internal::FlushParams const &flushParams)
318362
* meshesPath and particlesPath are stored there */
319363
Series s = retrieveSeries();
320364

321-
if (!meshes.empty() || s.containsAttribute("meshesPath"))
365+
if (hasMeshes())
322366
{
323367
if (!s.containsAttribute("meshesPath"))
324368
{
@@ -334,7 +378,7 @@ void Iteration::flush(internal::FlushParams const &flushParams)
334378
meshes.dirty() = false;
335379
}
336380

337-
if (!particles.empty() || s.containsAttribute("particlesPath"))
381+
if (hasParticles())
338382
{
339383
if (!s.containsAttribute("particlesPath"))
340384
{
@@ -496,6 +540,12 @@ void Iteration::read_impl(std::string const &groupPath)
496540
hasMeshes = s.containsAttribute("meshesPath");
497541
hasParticles = s.containsAttribute("particlesPath");
498542
}
543+
{
544+
using TB = internal::IterationData::TernaryBool;
545+
auto &data = get();
546+
data.hasMeshes = hasMeshes ? TB::True : TB::False;
547+
data.hasParticles = hasParticles ? TB::True : TB::False;
548+
}
499549

500550
if (hasMeshes)
501551
{

src/auxiliary/TemplateFile.cpp

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
#include "openPMD/auxiliary/TemplateFile.hpp"
2+
#include "openPMD/DatatypeHelpers.hpp"
3+
4+
#include <iostream>
5+
6+
namespace openPMD::auxiliary
7+
{
8+
namespace
9+
{
10+
// Some forward declarations
11+
template <typename T>
12+
void initializeFromTemplate(
13+
Container<T> &initializeMe, Container<T> const &fromTemplate);
14+
15+
struct SetAttribute
16+
{
17+
template <typename T>
18+
static void
19+
call(Attributable &object, std::string const &name, Attribute attr)
20+
{
21+
object.setAttribute(name, attr.get<T>());
22+
}
23+
24+
template <unsigned n>
25+
static void call(Attributable &, std::string const &name, Attribute)
26+
{
27+
std::cerr << "Unknown datatype for template attribute '" << name
28+
<< "'. Will skip it." << std::endl;
29+
}
30+
};
31+
32+
void copyAttributes(
33+
Attributable &target,
34+
Attributable const &source,
35+
std::vector<std::string> ignore = {})
36+
{
37+
auto shouldBeIgnored = [&ignore](std::string const &attrName) {
38+
// `ignore` is empty by default and normally has only a handful of
39+
// entries otherwise.
40+
// So just use linear search.
41+
for (auto const &ignored : ignore)
42+
{
43+
if (attrName == ignored)
44+
{
45+
return true;
46+
}
47+
}
48+
return false;
49+
};
50+
51+
for (auto const &attrName : source.attributes())
52+
{
53+
if (shouldBeIgnored(attrName))
54+
{
55+
continue;
56+
}
57+
auto attr = source.getAttribute(attrName);
58+
auto dtype = attr.dtype;
59+
switchType<SetAttribute>(dtype, target, attrName, std::move(attr));
60+
}
61+
}
62+
63+
void initializeFromTemplate(
64+
BaseRecordComponent &initializeMe,
65+
BaseRecordComponent const &fromTemplate)
66+
{
67+
copyAttributes(initializeMe, fromTemplate);
68+
}
69+
70+
void initializeFromTemplate(
71+
RecordComponent &initializeMe, RecordComponent const &fromTemplate)
72+
{
73+
if (fromTemplate.getDatatype() != Datatype::UNDEFINED)
74+
{
75+
initializeMe.resetDataset(
76+
Dataset{fromTemplate.getDatatype(), fromTemplate.getExtent()});
77+
}
78+
initializeFromTemplate(
79+
static_cast<BaseRecordComponent &>(initializeMe),
80+
static_cast<BaseRecordComponent const &>(fromTemplate));
81+
}
82+
83+
void initializeFromTemplate(
84+
PatchRecordComponent &initializeMe,
85+
PatchRecordComponent const &fromTemplate)
86+
{
87+
if (fromTemplate.getDatatype() != Datatype::UNDEFINED)
88+
{
89+
initializeMe.resetDataset(
90+
Dataset{fromTemplate.getDatatype(), fromTemplate.getExtent()});
91+
}
92+
initializeFromTemplate(
93+
static_cast<BaseRecordComponent &>(initializeMe),
94+
static_cast<BaseRecordComponent const &>(fromTemplate));
95+
}
96+
97+
void initializeFromTemplate(
98+
ParticleSpecies &initializeMe, ParticleSpecies const &fromTemplate)
99+
{
100+
if (!fromTemplate.particlePatches.empty())
101+
{
102+
initializeFromTemplate(
103+
static_cast<Container<PatchRecord> &>(
104+
initializeMe.particlePatches),
105+
static_cast<Container<PatchRecord> const &>(
106+
fromTemplate.particlePatches));
107+
}
108+
initializeFromTemplate(
109+
static_cast<Container<Record> &>(initializeMe),
110+
static_cast<Container<Record> const &>(fromTemplate));
111+
}
112+
113+
template <typename T>
114+
void initializeFromTemplate(
115+
Container<T> &initializeMe, Container<T> const &fromTemplate)
116+
{
117+
copyAttributes(initializeMe, fromTemplate);
118+
for (auto const &pair : fromTemplate)
119+
{
120+
initializeFromTemplate(initializeMe[pair.first], pair.second);
121+
}
122+
}
123+
124+
void initializeFromTemplate(
125+
Iteration &initializeMe, Iteration const &fromTemplate)
126+
{
127+
copyAttributes(initializeMe, fromTemplate, {"snapshot"});
128+
if (fromTemplate.hasMeshes())
129+
{
130+
initializeFromTemplate(initializeMe.meshes, fromTemplate.meshes);
131+
}
132+
if (fromTemplate.hasParticles())
133+
{
134+
initializeFromTemplate(
135+
initializeMe.particles, fromTemplate.particles);
136+
}
137+
}
138+
} // namespace
139+
140+
Series &initializeFromTemplate(
141+
Series &initializeMe, Series const &fromTemplate, uint64_t iteration)
142+
{
143+
if (!initializeMe.containsAttribute("from_template"))
144+
{
145+
copyAttributes(
146+
initializeMe,
147+
fromTemplate,
148+
{"basePath", "iterationEncoding", "iterationFormat", "openPMD"});
149+
initializeMe.setAttribute("from_template", fromTemplate.name());
150+
}
151+
152+
uint64_t sourceIteration = iteration;
153+
if (!fromTemplate.iterations.contains(sourceIteration))
154+
{
155+
if (fromTemplate.iterations.empty())
156+
{
157+
std::cerr << "Template file has no iterations, will only fill in "
158+
"global attributes."
159+
<< std::endl;
160+
return initializeMe;
161+
}
162+
else
163+
{
164+
sourceIteration = fromTemplate.iterations.begin()->first;
165+
}
166+
}
167+
168+
initializeFromTemplate(
169+
initializeMe.iterations[iteration],
170+
fromTemplate.iterations.at(sourceIteration));
171+
return initializeMe;
172+
}
173+
} // namespace openPMD::auxiliary

test/SerialIOTest.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "openPMD/auxiliary/Environment.hpp"
1111
#include "openPMD/auxiliary/Filesystem.hpp"
1212
#include "openPMD/auxiliary/StringManip.hpp"
13+
#include "openPMD/auxiliary/TemplateFile.hpp"
1314
#include "openPMD/openPMD.hpp"
1415

1516
#include <catch2/catch.hpp>
@@ -1461,6 +1462,12 @@ inline void dtype_test(
14611462

14621463
if (activateTemplateMode.has_value())
14631464
{
1465+
Series out(
1466+
"../samples/dtype_test_from_template." + backend,
1467+
Access::CREATE,
1468+
activateTemplateMode.value());
1469+
auxiliary::initializeFromTemplate(out, s, 1000);
1470+
out.flush();
14641471
return;
14651472
}
14661473
// same implementation types (not necessary aliases) detection

0 commit comments

Comments
 (0)