2525#include " openPMD/IO/IOTask.hpp"
2626#include " openPMD/RecordComponent.hpp"
2727#include " openPMD/Series.hpp"
28+ #include " openPMD/auxiliary/StringManip.hpp"
2829#include " openPMD/backend/Attributable.hpp"
2930
31+ #include < algorithm>
3032#include < deque>
3133#include < memory>
3234
@@ -36,7 +38,13 @@ namespace internal
3638{
3739 bool MeshesParticlesPath::ignore (const std::string &name) const
3840 {
39- return paths.find (name) != paths.end ();
41+ auto no_slashes = [](std::string const &str) {
42+ return auxiliary::trim (str, [](char const &c) { return c == ' /' ; });
43+ };
44+ return (meshesPath.has_value () &&
45+ name == no_slashes (meshesPath.value ())) ||
46+ (particlesPath.has_value () &&
47+ name == no_slashes (particlesPath.value ()));
4048 }
4149
4250 CustomHierarchyData::CustomHierarchyData ()
@@ -62,16 +70,200 @@ CustomHierarchy::CustomHierarchy()
6270CustomHierarchy::CustomHierarchy (NoInit) : Container_t(NoInit())
6371{}
6472
73+ void CustomHierarchy::readMeshes (std::string const &meshesPath)
74+ {
75+ Parameter<Operation::OPEN_PATH> pOpen;
76+ Parameter<Operation::LIST_PATHS> pList;
77+
78+ pOpen.path = meshesPath;
79+ IOHandler ()->enqueue (IOTask (&meshes, pOpen));
80+
81+ meshes.readAttributes (ReadMode::FullyReread);
82+
83+ internal::EraseStaleEntries<decltype (meshes)> map{meshes};
84+
85+ /* obtain all non-scalar meshes */
86+ IOHandler ()->enqueue (IOTask (&meshes, pList));
87+ IOHandler ()->flush (internal::defaultFlushParams);
88+
89+ Parameter<Operation::LIST_ATTS> aList;
90+ for (auto const &mesh_name : *pList.paths )
91+ {
92+ Mesh &m = map[mesh_name];
93+ pOpen.path = mesh_name;
94+ aList.attributes ->clear ();
95+ IOHandler ()->enqueue (IOTask (&m, pOpen));
96+ IOHandler ()->enqueue (IOTask (&m, aList));
97+ IOHandler ()->flush (internal::defaultFlushParams);
98+
99+ auto att_begin = aList.attributes ->begin ();
100+ auto att_end = aList.attributes ->end ();
101+ auto value = std::find (att_begin, att_end, " value" );
102+ auto shape = std::find (att_begin, att_end, " shape" );
103+ if (value != att_end && shape != att_end)
104+ {
105+ MeshRecordComponent &mrc = m;
106+ IOHandler ()->enqueue (IOTask (&mrc, pOpen));
107+ IOHandler ()->flush (internal::defaultFlushParams);
108+ mrc.get ().m_isConstant = true ;
109+ }
110+ m.read ();
111+ try
112+ {
113+ m.read ();
114+ }
115+ catch (error::ReadError const &err)
116+ {
117+ std::cerr << " Cannot read mesh with name '" << mesh_name
118+ << " ' and will skip it due to read error:\n "
119+ << err.what () << std::endl;
120+ map.forget (mesh_name);
121+ }
122+ }
123+
124+ /* obtain all scalar meshes */
125+ Parameter<Operation::LIST_DATASETS> dList;
126+ IOHandler ()->enqueue (IOTask (&meshes, dList));
127+ IOHandler ()->flush (internal::defaultFlushParams);
128+
129+ Parameter<Operation::OPEN_DATASET> dOpen;
130+ for (auto const &mesh_name : *dList.datasets )
131+ {
132+ Mesh &m = map[mesh_name];
133+ dOpen.name = mesh_name;
134+ IOHandler ()->enqueue (IOTask (&m, dOpen));
135+ IOHandler ()->flush (internal::defaultFlushParams);
136+ MeshRecordComponent &mrc = m;
137+ IOHandler ()->enqueue (IOTask (&mrc, dOpen));
138+ IOHandler ()->flush (internal::defaultFlushParams);
139+ mrc.written () = false ;
140+ mrc.resetDataset (Dataset (*dOpen.dtype , *dOpen.extent ));
141+ mrc.written () = true ;
142+ try
143+ {
144+ m.read ();
145+ }
146+ catch (error::ReadError const &err)
147+ {
148+ std::cerr << " Cannot read mesh with name '" << mesh_name
149+ << " ' and will skip it due to read error:\n "
150+ << err.what () << std::endl;
151+ map.forget (mesh_name);
152+ }
153+ }
154+ }
155+
156+ void CustomHierarchy::readParticles (std::string const &particlesPath)
157+ {
158+ Parameter<Operation::OPEN_PATH> pOpen;
159+ Parameter<Operation::LIST_PATHS> pList;
160+
161+ pOpen.path = particlesPath;
162+ IOHandler ()->enqueue (IOTask (&particles, pOpen));
163+
164+ particles.readAttributes (ReadMode::FullyReread);
165+
166+ /* obtain all particle species */
167+ pList.paths ->clear ();
168+ IOHandler ()->enqueue (IOTask (&particles, pList));
169+ IOHandler ()->flush (internal::defaultFlushParams);
170+
171+ internal::EraseStaleEntries<decltype (particles)> map{particles};
172+ for (auto const &species_name : *pList.paths )
173+ {
174+ ParticleSpecies &p = map[species_name];
175+ pOpen.path = species_name;
176+ IOHandler ()->enqueue (IOTask (&p, pOpen));
177+ IOHandler ()->flush (internal::defaultFlushParams);
178+ try
179+ {
180+ p.read ();
181+ }
182+ catch (error::ReadError const &err)
183+ {
184+ std::cerr << " Cannot read particle species with name '"
185+ << species_name
186+ << " ' and will skip it due to read error:\n "
187+ << err.what () << std::endl;
188+ map.forget (species_name);
189+ }
190+ }
191+ }
192+
65193void CustomHierarchy::read (internal::MeshesParticlesPath const &mpp)
66194{
67195 /*
68196 * Convention for CustomHierarchy::flush and CustomHierarchy::read:
69197 * Path is created/opened already at entry point of method, method needs
70198 * to create/open path for contained subpaths.
71199 */
72- Attributable::readAttributes (ReadMode::FullyReread);
200+
73201 Parameter<Operation::LIST_PATHS> pList;
74202 IOHandler ()->enqueue (IOTask (this , pList));
203+ IOHandler ()->flush (internal::defaultFlushParams);
204+
205+ auto thisGroupHasMeshesOrParticles =
206+ [&pList](std::optional<std::string> meshesOrParticlesPath) -> bool {
207+ if (!meshesOrParticlesPath.has_value ())
208+ {
209+ return false ;
210+ }
211+ auto no_slashes = [](std::string const &str) {
212+ return auxiliary::trim (str, [](char const &c) { return c == ' /' ; });
213+ };
214+ std::string look_for = no_slashes (meshesOrParticlesPath.value ());
215+ auto const &paths = *pList.paths ;
216+ return std::find_if (
217+ paths.begin (),
218+ paths.end (),
219+ [&no_slashes, &look_for](std::string const &entry) {
220+ return no_slashes (entry) == look_for;
221+ }) != paths.end ();
222+ };
223+
224+ if (thisGroupHasMeshesOrParticles (mpp.meshesPath ))
225+ {
226+ try
227+ {
228+ readMeshes (mpp.meshesPath .value ());
229+ }
230+ catch (error::ReadError const &err)
231+ {
232+ std::cerr << " Cannot read meshes at location '"
233+ << myPath ().printGroup ()
234+ << " ' and will skip them due to read error:\n "
235+ << err.what () << std::endl;
236+ meshes = {};
237+ meshes.dirty () = false ;
238+ }
239+ }
240+ else
241+ {
242+ meshes.dirty () = false ;
243+ }
244+
245+ if (thisGroupHasMeshesOrParticles (mpp.particlesPath ))
246+ {
247+ try
248+ {
249+ readParticles (mpp.particlesPath .value ());
250+ }
251+ catch (error::ReadError const &err)
252+ {
253+ std::cerr << " Cannot read particles at location '"
254+ << myPath ().printGroup ()
255+ << " ' and will skip them due to read error:\n "
256+ << err.what () << std::endl;
257+ particles = {};
258+ particles.dirty () = false ;
259+ }
260+ }
261+ else
262+ {
263+ particles.dirty () = false ;
264+ }
265+
266+ Attributable::readAttributes (ReadMode::FullyReread);
75267 Parameter<Operation::LIST_DATASETS> dList;
76268 IOHandler ()->enqueue (IOTask (this , dList));
77269 IOHandler ()->flush (internal::defaultFlushParams);
@@ -147,7 +339,7 @@ void CustomHierarchy::flush(
147339 * meshesPath and particlesPath are stored there */
148340 Series s = retrieveSeries ();
149341
150- if (!meshes.empty () || s. containsAttribute ( " meshesPath " ) )
342+ if (!meshes.empty ())
151343 {
152344 if (!s.containsAttribute (" meshesPath" ))
153345 {
@@ -163,7 +355,7 @@ void CustomHierarchy::flush(
163355 meshes.dirty () = false ;
164356 }
165357
166- if (!particles.empty () || s. containsAttribute ( " particlesPath " ) )
358+ if (!particles.empty ())
167359 {
168360 if (!s.containsAttribute (" particlesPath" ))
169361 {
0 commit comments