38
38
#include < optional>
39
39
#include < regex>
40
40
#include < sstream>
41
+ #include < tuple>
41
42
42
43
namespace openPMD
43
44
{
44
45
45
46
namespace
46
47
{
48
+ template <typename Iterator>
47
49
std::string
48
- concatWithSep (std::vector<std::string> const &v , std::string const &sep)
50
+ concatWithSep (Iterator &&begin, Iterator const &end , std::string const &sep)
49
51
{
50
- switch (v. size () )
52
+ if (begin == end )
51
53
{
52
- case 0 :
53
54
return " " ;
54
- case 1 :
55
- return *v.begin ();
56
- default :
57
- break ;
58
55
}
59
56
std::stringstream res;
60
- auto it = v.begin ();
61
- res << *it++;
62
- for (; it != v.end (); ++it)
57
+ res << *(begin++);
58
+ for (; begin != end; ++begin)
63
59
{
64
- res << sep << *it ;
60
+ res << sep << *begin ;
65
61
}
66
62
return res.str ();
67
63
}
68
64
65
+ std::string
66
+ concatWithSep (std::vector<std::string> const &v, std::string const &sep)
67
+ {
68
+ return concatWithSep (v.begin (), v.end (), sep);
69
+ }
70
+
69
71
// Not specifying std::regex_constants::optimize here, only using it where
70
72
// it makes sense to.
71
73
constexpr std::regex_constants::syntax_option_type regex_flags =
72
74
std::regex_constants::egrep;
75
+
76
+ template <typename OutParam>
77
+ void setDefaultMeshesParticlesPath (
78
+ std::vector<std::string> const &meshes,
79
+ std::vector<std::string> const &particles,
80
+ OutParam &writeTarget)
81
+ {
82
+ std::regex is_default_path_specification (" [[:alnum:]_]+/" , regex_flags);
83
+ constexpr char const *default_default_mesh = " meshes" ;
84
+ constexpr char const *default_default_particle = " particles" ;
85
+ for (auto [vec, defaultPath, default_default] :
86
+ {std::make_tuple (
87
+ &meshes,
88
+ &writeTarget.m_defaultMeshesPath ,
89
+ default_default_mesh),
90
+ std::make_tuple (
91
+ &particles,
92
+ &writeTarget.m_defaultParticlesPath ,
93
+ default_default_particle)})
94
+ {
95
+ bool set_default = true ;
96
+ /*
97
+ * The first eligible path in meshesPath/particlesPath is used as
98
+ * the default, "meshes"/"particles" otherwise.
99
+ */
100
+ for (auto const &path : *vec)
101
+ {
102
+ if (std::regex_match (path, is_default_path_specification))
103
+ {
104
+ *defaultPath = auxiliary::replace_last (path, " /" , " " );
105
+ set_default = false ;
106
+ break ;
107
+ }
108
+ }
109
+ if (set_default)
110
+ {
111
+ *defaultPath = default_default;
112
+ }
113
+ }
114
+ }
73
115
} // namespace
74
116
75
117
namespace internal
@@ -81,15 +123,43 @@ namespace internal
81
123
std::vector<std::string> const &path,
82
124
std::string const &name)
83
125
{
84
- std::string parentPath =
85
- (path.empty () ? " " : concatWithSep (path, " /" )) + " /" ;
86
- std::string fullPath = path.empty () ? name : parentPath + name;
126
+ /*
127
+ * /group/meshes/E is a mesh if the meshes path contains:
128
+ *
129
+ * 1) '/group/meshes/' (absolute path to mesh container)
130
+ * 2) '/group/meshes/E' (absolute path to mesh itself)
131
+ * 3) 'meshes/' (relative path to mesh container)
132
+ *
133
+ * The potential fourth option 'E' (relative path to mesh itself)
134
+ * is not supported. ("Anything that is named 'E' is a mesh" is not
135
+ * really a semantic that we want to explicitly support.)
136
+ * '/' is never a valid meshes path.
137
+ *
138
+ * All this analogously for particles path.
139
+ */
140
+ std::vector<std::string> pathsToMatch = {
141
+ /* option 2) from above */
142
+ " /" + (path.empty () ? " " : concatWithSep (path, " /" ) + " /" ) +
143
+ name};
144
+ if (!path.empty ())
145
+ {
146
+ // option 1) from above
147
+ pathsToMatch.emplace_back (" /" + concatWithSep (path, " /" ) + " /" );
148
+
149
+ // option 3 from above
150
+ pathsToMatch.emplace_back (*path.rbegin () + " /" );
151
+ }
87
152
return std::any_of (
88
153
regexes.begin (),
89
154
regexes.end (),
90
- [&parentPath, &fullPath](auto const ®ex) {
91
- return std::regex_match (parentPath, regex.second ) ||
92
- std::regex_match (fullPath, regex.second );
155
+ [&pathsToMatch](auto const ®ex) {
156
+ return std::any_of (
157
+ pathsToMatch.begin (),
158
+ pathsToMatch.end (),
159
+ [®ex](std::string const &candidate_path) {
160
+ return std::regex_match (
161
+ candidate_path, regex.second );
162
+ });
93
163
});
94
164
}
95
165
} // namespace
@@ -98,9 +168,11 @@ namespace internal
98
168
std::vector<std::string> const &meshes,
99
169
std::vector<std::string> const &particles)
100
170
{
101
- for (auto [deque, vec] :
102
- {std::make_pair (&this ->meshesPath , &meshes),
103
- std::make_pair (&this ->particlesPath , &particles)})
171
+ std::regex is_default_path_specification (" [[:alnum:]_]+/" , regex_flags);
172
+ for (auto [deque, vec, defaultPath] :
173
+ {std::make_tuple (&this ->meshesPath , &meshes, &m_defaultMeshesPath),
174
+ std::make_tuple (
175
+ &this ->particlesPath , &particles, &m_defaultParticlesPath)})
104
176
{
105
177
std::transform (
106
178
vec->begin (),
@@ -113,6 +185,7 @@ namespace internal
113
185
str, regex_flags | std::regex_constants::optimize));
114
186
});
115
187
}
188
+ setDefaultMeshesParticlesPath (meshes, particles, *this );
116
189
}
117
190
118
191
ContainedType MeshesParticlesPath::determineType (
@@ -262,10 +335,6 @@ void CustomHierarchy::readParticleSpecies(
262
335
}
263
336
}
264
337
265
- // @todo make this flexible again
266
- constexpr char const *defaultMeshesPath = " meshes" ;
267
- constexpr char const *defaultParticlesPath = " particles" ;
268
-
269
338
void CustomHierarchy::read (internal::MeshesParticlesPath const &mpp)
270
339
{
271
340
std::vector<std::string> currentPath;
@@ -292,6 +361,8 @@ void CustomHierarchy::read(
292
361
293
362
std::deque<std::string> constantComponentsPushback;
294
363
auto &data = get ();
364
+ data.m_defaultMeshesPath = mpp.m_defaultMeshesPath ;
365
+ data.m_defaultParticlesPath = mpp.m_defaultParticlesPath ;
295
366
EraseStaleMeshes meshesMap (data.m_embeddedMeshes );
296
367
EraseStaleParticles particlesMap (data.m_embeddedParticles );
297
368
for (auto const &path : *pList.paths )
@@ -405,16 +476,19 @@ void CustomHierarchy::flush_internal(
405
476
406
477
// No need to do anything in access::readOnly since meshes and particles
407
478
// are initialized as aliases for subgroups at parsing time
479
+ auto &data = get ();
480
+ data.m_defaultMeshesPath = mpp.m_defaultMeshesPath ;
481
+ data.m_defaultParticlesPath = mpp.m_defaultParticlesPath ;
408
482
if (access::write (IOHandler ()->m_frontendAccess ))
409
483
{
410
484
if (!meshes.empty ())
411
485
{
412
- (*this )[defaultMeshesPath ];
486
+ (*this )[mpp. m_defaultMeshesPath ];
413
487
}
414
488
415
489
if (!particles.empty ())
416
490
{
417
- (*this )[defaultParticlesPath ];
491
+ (*this )[mpp. m_defaultParticlesPath ];
418
492
}
419
493
420
494
flushAttributes (flushParams);
@@ -432,27 +506,53 @@ void CustomHierarchy::flush_internal(
432
506
subpath.flush_internal (flushParams, mpp, currentPath);
433
507
currentPath.pop_back ();
434
508
}
435
- auto &data = get ();
436
509
for (auto &[name, mesh] : data.m_embeddedMeshes )
437
510
{
438
511
if (!mpp.isMesh (currentPath, name))
439
512
{
440
- std::string fullPath = currentPath.empty ()
441
- ? name
442
- : concatWithSep (currentPath, " /" ) + " /" + name;
443
- mpp.meshesPath .emplace (fullPath, std::regex (fullPath, regex_flags));
513
+ std::string extend_meshes_path;
514
+ if (!currentPath.empty () &&
515
+ *currentPath.rbegin () == mpp.m_defaultMeshesPath )
516
+ {
517
+ extend_meshes_path = *currentPath.rbegin () + " /" ;
518
+ }
519
+ else
520
+ {
521
+
522
+ extend_meshes_path = " /" +
523
+ (currentPath.empty ()
524
+ ? " "
525
+ : concatWithSep (currentPath, " /" ) + " /" ) +
526
+ name;
527
+ }
528
+ mpp.meshesPath .emplace (
529
+ extend_meshes_path,
530
+ std::regex (extend_meshes_path, regex_flags));
444
531
}
445
532
mesh.flush (name, flushParams);
446
533
}
447
534
for (auto &[name, particleSpecies] : data.m_embeddedParticles )
448
535
{
449
536
if (!mpp.isParticle (currentPath, name))
450
537
{
451
- std::string fullPath = currentPath.empty ()
452
- ? name
453
- : concatWithSep (currentPath, " /" ) + " /" + name;
538
+ std::string extend_particles_path;
539
+ if (!currentPath.empty () &&
540
+ *currentPath.rbegin () == mpp.m_defaultParticlesPath )
541
+ {
542
+ extend_particles_path = *currentPath.rbegin () + " /" ;
543
+ }
544
+ else
545
+ {
546
+
547
+ extend_particles_path = " /" +
548
+ (currentPath.empty ()
549
+ ? " "
550
+ : concatWithSep (currentPath, " /" ) + " /" ) +
551
+ name;
552
+ }
454
553
mpp.particlesPath .emplace (
455
- fullPath, std::regex (fullPath, regex_flags));
554
+ extend_particles_path,
555
+ std::regex (extend_particles_path, regex_flags));
456
556
}
457
557
particleSpecies.flush (name, flushParams);
458
558
}
@@ -596,10 +696,11 @@ template <typename KeyType>
596
696
auto CustomHierarchy::bracketOperatorImpl (KeyType &&provided_key)
597
697
-> mapped_type &
598
698
{
599
- auto &cont = container ();
699
+ auto &data = get ();
700
+ auto &cont = data.m_container ;
600
701
auto find_special_key =
601
702
[&cont, &provided_key, this ](
602
- char const * special_key,
703
+ std::string const & special_key,
603
704
auto &alias,
604
705
auto &&embeddedAccessor) -> std::optional<mapped_type *> {
605
706
if (provided_key == special_key)
@@ -656,8 +757,15 @@ auto CustomHierarchy::bracketOperatorImpl(KeyType &&provided_key)
656
757
return std::nullopt ;
657
758
}
658
759
};
760
+ if (data.m_defaultMeshesPath .empty () || data.m_defaultParticlesPath .empty ())
761
+ {
762
+ auto const &series = retrieveSeries ();
763
+ auto meshes_paths = series.meshesPaths ();
764
+ auto particles_paths = series.particlesPaths ();
765
+ setDefaultMeshesParticlesPath (meshes_paths, particles_paths, data);
766
+ }
659
767
if (auto res = find_special_key (
660
- defaultMeshesPath ,
768
+ data. m_defaultMeshesPath ,
661
769
meshes,
662
770
[](auto &group) {
663
771
return &group.m_customHierarchyData ->m_embeddedMeshes ;
@@ -667,7 +775,7 @@ auto CustomHierarchy::bracketOperatorImpl(KeyType &&provided_key)
667
775
return **res;
668
776
}
669
777
if (auto res = find_special_key (
670
- defaultParticlesPath ,
778
+ data. m_defaultParticlesPath ,
671
779
particles,
672
780
[](auto &group) {
673
781
return &group.m_customHierarchyData ->m_embeddedParticles ;
0 commit comments