Skip to content

Commit

Permalink
More symmetric design for container types
Browse files Browse the repository at this point in the history
  • Loading branch information
franzpoeschel committed Oct 26, 2023
1 parent af4f318 commit 137982f
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 88 deletions.
111 changes: 92 additions & 19 deletions include/openPMD/CustomHierarchy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "openPMD/IO/AbstractIOHandler.hpp"
#include "openPMD/Mesh.hpp"
#include "openPMD/ParticleSpecies.hpp"
#include "openPMD/RecordComponent.hpp"
#include "openPMD/backend/Container.hpp"

#include <memory>
Expand Down Expand Up @@ -74,27 +75,67 @@ namespace internal
isMeshContainer(std::vector<std::string> const &path) const;
};

struct CustomHierarchyData : ContainerData<CustomHierarchy>
struct CustomHierarchyData
: ContainerData<CustomHierarchy>
, ContainerData<RecordComponent>
, ContainerData<Mesh>
, ContainerData<ParticleSpecies>
{
explicit CustomHierarchyData();

void syncAttributables();

Container<RecordComponent> m_embeddedDatasets;
Container<Mesh> m_embeddedMeshes;
Container<ParticleSpecies> m_embeddedParticles;
Container<CustomHierarchy> customHierarchies()
{
Container<CustomHierarchy> res;
res.setData(
{static_cast<ContainerData<CustomHierarchy> *>(this),
[](auto const *) {}});
return res;
}
Container<RecordComponent> embeddedDatasets()
{
Container<RecordComponent> res;
res.setData(
{static_cast<ContainerData<RecordComponent> *>(this),
[](auto const *) {}});
return res;
}
Container<Mesh> embeddedMeshes()
{
Container<Mesh> res;
res.setData(
{static_cast<ContainerData<Mesh> *>(this),
[](auto const *) {}});
return res;
}

Container<ParticleSpecies> embeddedParticles()
{
Container<ParticleSpecies> res;
res.setData(
{static_cast<ContainerData<ParticleSpecies> *>(this),
[](auto const *) {}});
return res;
}
};
} // namespace internal

class CustomHierarchy : public Container<CustomHierarchy>
template <typename MappedType>
class ConversibleContainer : public Container<MappedType>
{
friend class Iteration;
friend class Container<CustomHierarchy>;
template <typename>
friend class ConversibleContainer;

private:
using Container_t = Container<CustomHierarchy>;
protected:
using Container_t = Container<MappedType>;
using Data_t = internal::CustomHierarchyData;
static_assert(std::is_base_of_v<Container_t::ContainerData, Data_t>);
static_assert(
std::is_base_of_v<typename Container_t::ContainerData, Data_t>);

ConversibleContainer(Attributable::NoInit)
: Container_t(Attributable::NoInit{})
{}

std::shared_ptr<Data_t> m_customHierarchyData;

Expand All @@ -107,6 +148,47 @@ class CustomHierarchy : public Container<CustomHierarchy>
return *m_customHierarchyData;
}

inline void setData(std::shared_ptr<Data_t> data)
{
m_customHierarchyData = data;
Container_t::setData(std::move(data));
}

public:
template <typename TargetType>
auto asContainerOf() -> ConversibleContainer<TargetType>
{
if constexpr (
std::is_same_v<TargetType, CustomHierarchy> ||
std::is_same_v<TargetType, Mesh> ||
std::is_same_v<TargetType, ParticleSpecies> ||
std::is_same_v<TargetType, RecordComponent>)
{
ConversibleContainer<TargetType> res(Attributable::NoInit{});
res.setData(m_customHierarchyData);
return res;
}
else
{
static_assert(
auxiliary::dependent_false_v<TargetType>,
"[CustomHierarchy::asContainerOf] Type parameter must be "
"one of: CustomHierarchy, RecordComponent, Mesh, "
"ParticleSpecies.");
}
}
};

class CustomHierarchy : public ConversibleContainer<CustomHierarchy>
{
friend class Iteration;
friend class Container<CustomHierarchy>;

private:
using Container_t = Container<CustomHierarchy>;
using Parent_t = ConversibleContainer<CustomHierarchy>;
using Data_t = typename Parent_t::Data_t;

using EraseStaleMeshes = internal::EraseStaleEntries<Container<Mesh>>;
using EraseStaleParticles =
internal::EraseStaleEntries<Container<ParticleSpecies>>;
Expand All @@ -118,12 +200,6 @@ class CustomHierarchy : public Container<CustomHierarchy>
CustomHierarchy();
CustomHierarchy(NoInit);

inline void setData(std::shared_ptr<Data_t> data)
{
m_customHierarchyData = data;
Container_t::setData(std::move(data));
}

void read(internal::MeshesParticlesPath const &);
void read(
internal::MeshesParticlesPath const &,
Expand Down Expand Up @@ -158,8 +234,5 @@ class CustomHierarchy : public Container<CustomHierarchy>

CustomHierarchy &operator=(CustomHierarchy const &) = default;
CustomHierarchy &operator=(CustomHierarchy &&) = default;

template <typename ContainedType>
auto asContainerOf() -> Container<ContainedType> &;
};
} // namespace openPMD
81 changes: 26 additions & 55 deletions src/CustomHierarchy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -262,21 +262,29 @@ namespace internal
/*
* m_embeddeddatasets and its friends should point to the same instance
* of Attributable.
* Not strictly necessary to do this explicitly due to virtual
* inheritance (all Attributable instances are the same anyway),
* but let's be explicit about this.
*/
for (auto p : std::initializer_list<Attributable *>{
&m_embeddedDatasets, &m_embeddedMeshes, &m_embeddedParticles})
for (auto p : std::initializer_list<AttributableData *>{
static_cast<ContainerData<CustomHierarchy> *>(this),
static_cast<ContainerData<RecordComponent> *>(this),
static_cast<ContainerData<Mesh> *>(this),
static_cast<ContainerData<ParticleSpecies> *>(this)})
{
p->m_attri->asSharedPtrOfAttributable() =
this->asSharedPtrOfAttributable();
p->asSharedPtrOfAttributable() = this->asSharedPtrOfAttributable();
}
}
} // namespace internal

CustomHierarchy::CustomHierarchy()
// template
// class ConversibleContainer<CustomHierarchy>;

CustomHierarchy::CustomHierarchy() : ConversibleContainer(NoInit{})
{
setData(std::make_shared<Data_t>());
}
CustomHierarchy::CustomHierarchy(NoInit) : Container_t(NoInit())
CustomHierarchy::CustomHierarchy(NoInit) : ConversibleContainer(NoInit{})
{}

void CustomHierarchy::readNonscalarMesh(
Expand Down Expand Up @@ -394,8 +402,8 @@ void CustomHierarchy::read(

std::deque<std::string> constantComponentsPushback;
auto &data = get();
EraseStaleMeshes meshesMap(data.m_embeddedMeshes);
EraseStaleParticles particlesMap(data.m_embeddedParticles);
EraseStaleMeshes meshesMap(data.embeddedMeshes());
EraseStaleParticles particlesMap(data.embeddedParticles());
for (auto const &path : *pList.paths)
{
switch (mpp.determineType(currentPath))
Expand Down Expand Up @@ -469,7 +477,7 @@ void CustomHierarchy::read(
// Group is a bit of an internal misnomer here, it just means that
// it matches neither meshes nor particles path
case internal::ContainedType::Group: {
auto &rc = data.m_embeddedDatasets[path];
auto &rc = data.embeddedDatasets()[path];
Parameter<Operation::OPEN_DATASET> dOpen;
dOpen.name = path;
IOHandler()->enqueue(IOTask(&rc, dOpen));
Expand All @@ -487,7 +495,7 @@ void CustomHierarchy::read(
<< "' at path '" << myPath().printGroup()
<< "' and will skip it due to read error:\n"
<< err.what() << std::endl;
data.m_embeddedDatasets.container().erase(path);
data.embeddedDatasets().container().erase(path);
}
break;
}
Expand Down Expand Up @@ -518,7 +526,7 @@ void CustomHierarchy::read(

for (auto const &path : constantComponentsPushback)
{
auto &rc = data.m_embeddedDatasets[path];
auto &rc = data.embeddedDatasets()[path];
try
{
Parameter<Operation::OPEN_PATH> pOpen;
Expand All @@ -533,7 +541,7 @@ void CustomHierarchy::read(
<< myPath().printGroup() << "/" << path
<< "' and will skip it due to read error:\n"
<< err.what() << std::endl;
data.m_embeddedDatasets.container().erase(path);
data.embeddedDatasets().container().erase(path);
}
}
}
Expand Down Expand Up @@ -569,7 +577,7 @@ void CustomHierarchy::flush_internal(
subpath.flush_internal(flushParams, mpp, currentPath);
currentPath.pop_back();
}
for (auto &[name, mesh] : data.m_embeddedMeshes)
for (auto &[name, mesh] : data.embeddedMeshes())
{
if (!mpp.isMeshContainer(currentPath))
{
Expand All @@ -593,7 +601,7 @@ void CustomHierarchy::flush_internal(
}
mesh.flush(name, flushParams);
}
for (auto &[name, particleSpecies] : data.m_embeddedParticles)
for (auto &[name, particleSpecies] : data.embeddedParticles())
{
if (!mpp.isParticleContainer(currentPath))
{
Expand All @@ -619,7 +627,7 @@ void CustomHierarchy::flush_internal(
}
particleSpecies.flush(name, flushParams);
}
for (auto &[name, dataset] : get().m_embeddedDatasets)
for (auto &[name, dataset] : get().embeddedDatasets())
{
dataset.flush(name, flushParams);
}
Expand Down Expand Up @@ -654,47 +662,10 @@ bool CustomHierarchy::dirtyRecursive() const
}
return false;
};
auto &data = get();
return check(data.m_embeddedMeshes) || check(data.m_embeddedParticles) ||
check(data.m_embeddedDatasets) || check(*this);
}

template <typename ContainedType>
auto CustomHierarchy::asContainerOf() -> Container<ContainedType> &
{
if constexpr (std::is_same_v<ContainedType, CustomHierarchy>)
{
return *static_cast<Container<CustomHierarchy> *>(this);
}
else if constexpr (std::is_same_v<ContainedType, Mesh>)
{
return get().m_embeddedMeshes;
}
else if constexpr (std::is_same_v<ContainedType, ParticleSpecies>)
{
return get().m_embeddedParticles;
}
else if constexpr (std::is_same_v<ContainedType, RecordComponent>)
{
return get().m_embeddedDatasets;
}
else
{
static_assert(
auxiliary::dependent_false_v<ContainedType>,
"[CustomHierarchy::asContainerOf] Type parameter must be "
"one of: CustomHierarchy, RecordComponent, Mesh, "
"ParticleSpecies.");
}
auto &data = const_cast<Data_t &>(get()); // @todo do this better
return check(data.embeddedMeshes()) || check(data.embeddedParticles()) ||
check(data.embeddedDatasets()) || check(data.customHierarchies());
}

template auto CustomHierarchy::asContainerOf<CustomHierarchy>()
-> Container<CustomHierarchy> &;
template auto CustomHierarchy::asContainerOf<RecordComponent>()
-> Container<RecordComponent> &;
template auto CustomHierarchy::asContainerOf<Mesh>() -> Container<Mesh> &;
template auto CustomHierarchy::asContainerOf<ParticleSpecies>()
-> Container<ParticleSpecies> &;
} // namespace openPMD

#undef OPENPMD_LEGAL_IDENTIFIER_CHARS
Expand Down
4 changes: 2 additions & 2 deletions src/Iteration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ void Iteration::sync_meshes_and_particles_from_alias_to_subgroups(
{
return;
}
auto &container = (*this)[defaultPath].asContainerOf<type>();
auto container = (*this)[defaultPath].asContainerOf<type>();

for (auto &[name, entry] : m_or_p)
{
Expand Down Expand Up @@ -415,7 +415,7 @@ void Iteration::sync_meshes_and_particles_from_subgroups_to_alias(
{
return;
}
auto &container = it->second.asContainerOf<type>();
auto container = it->second.asContainerOf<type>();
for (auto &[name, entry] : container)
{
m_or_p.emplace(name, entry);
Expand Down
40 changes: 31 additions & 9 deletions src/binding/python/CustomHierarchy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,43 @@
namespace py = pybind11;
using namespace openPMD;

template <typename MappedType>
void define_conversible_container(py::module &m, std::string const &name)
{
using CC = ConversibleContainer<MappedType>;
py::class_<CC, Container<MappedType>, Attributable>(m, name.c_str())
.def(
"as_container_of_datasets",
&CC::template asContainerOf<RecordComponent>)
.def("as_container_of_meshes", &CC::template asContainerOf<Mesh>)
.def(
"as_container_of_particles",
&CC::template asContainerOf<ParticleSpecies>)
.def(
"as_container_of_custom_hierarchy",
&CC::template asContainerOf<CustomHierarchy>);
}

void init_CustomHierarchy(py::module &m)
{
auto py_ch_cont =
declare_container<PyCustomHierarchyContainer, Attributable>(
m, "Container_CustomHierarchy");

py::class_<CustomHierarchy, Container<CustomHierarchy>, Attributable>(
m, "CustomHierarchy")
.def(
"as_container_of_datasets",
&CustomHierarchy::asContainerOf<RecordComponent>)
.def("as_container_of_meshes", &CustomHierarchy::asContainerOf<Mesh>)
.def(
"as_container_of_particles",
&CustomHierarchy::asContainerOf<ParticleSpecies>);
define_conversible_container<CustomHierarchy>(
m, "ConversibleContainer_CustomHierarchy");
define_conversible_container<ParticleSpecies>(
m, "ConversibleContainer_ParticleSpecies");
define_conversible_container<RecordComponent>(
m, "ConversibleContainer_RecordComponent");
define_conversible_container<Mesh>(m, "ConversibleContainer_Mesh");

[[maybe_unused]] py::class_<
CustomHierarchy,
ConversibleContainer<CustomHierarchy>,
Container<CustomHierarchy>,
Attributable>
custom_hierarchy(m, "CustomHierarchy");

finalize_container<PyCustomHierarchyContainer>(py_ch_cont);
}
Loading

0 comments on commit 137982f

Please sign in to comment.