group_particles
Loading...
Searching...
No Matches
fields.hpp
Go to the documentation of this file.
1
8#ifndef FIELDS_HPP
9#define FIELDS_HPP
10
11#include <initializer_list>
12#include <type_traits>
13#include <cmath>
14#include <cstdlib>
15#include <cstring>
16
17#ifndef NDEBUG
18# include <cstdio>
19#endif // NDEBUG
20
28using coord_t = float;
29
32enum class FieldTypes
33{
34 GrpFld,
35 PrtFld,
36};
37
50#define FIELD(name_, dim_, value_type_, type_, coord_) \
51 struct name_ \
52 { \
53 name_ () = delete; \
54 static constexpr const char name[] = #name_; \
55 static constexpr const size_t size = sizeof(value_type_); \
56 static constexpr const size_t size_fcoord \
57 = (coord_) ? sizeof(coord_t) : size; \
58 static constexpr const size_t dim = dim_; \
59 static constexpr const size_t stride = dim_ * size; \
60 static constexpr const size_t stride_fcoord \
61 = dim_ * size_fcoord; \
62 static constexpr const FieldTypes type = type_; \
63 static constexpr const bool coord = coord_; \
64 using value_type = value_type_; \
65 static_assert(!coord_ || dim_==3, \
66 "Non-3dimensional coordinate field "#name_); \
67 static_assert(!coord_ \
68 || std::is_floating_point_v<value_type_>, \
69 "Non-float coordinate field "#name_ \
70 " not supported"); \
71 }
72
83template<FieldTypes field_type_, typename... Fields>
85{//{{{
86 static constexpr bool all_valid (std::initializer_list<FieldTypes> types)
87 {// {{{
88 for (auto t : types)
89 if (t != field_type_) return false;
90 return true;
91 }// }}}
92
93 template<typename first_field, typename... other_fields>
94 static constexpr bool first_field_is_coord ()
95 {// {{{
96 return first_field::coord;
97 }// }}}
98
99 static constexpr bool str_equ (const char *str1, const char *str2)
100 {// {{{
101 // this function simply does the same as C strcmp, but as a constexpr
102 return *str1==*str2 && ( *str1=='\0' || str_equ(str1+1, str2+1) );
103 }// }}}
104
105 template<typename first_field>
106 static constexpr bool all_unequal ()
107 { return true; }
108
109 template<typename first_field, typename second_field, typename... other_fields>
110 static constexpr bool all_unequal ()
111 {// {{{
112 constexpr bool first_two = !std::is_same_v<first_field,second_field>;
113 if constexpr ((bool)sizeof...(other_fields))
114 return first_two
115 && all_unequal<first_field, other_fields...>()
116 && all_unequal<second_field, other_fields...>();
117 else
118 return first_two;
119 }// }}}
120
121 template<typename to_find, typename first_field, typename... other_fields>
122 static constexpr size_t find_idx (size_t idx_of_first = 0UL)
123 {// {{{
124 if constexpr (std::is_same_v<to_find, first_field>)
125 return idx_of_first;
126 else
127 {
128 static_assert( sizeof...(other_fields),
129 "Requested index of field that is not contained in collection." );
130 return find_idx<to_find, other_fields...>(idx_of_first+1UL);
131 }
132 }// }}}
133
134 template<typename first_field, typename... other_fields>
135 struct extract_coord_type
136 {// {{{
137 using value_type = typename first_field::value_type;
138 };// }}}
139public :
140 // this is only a type, no instances of it can be created
141 FieldCollection () = delete;
142
143 static constexpr const size_t Nfields = sizeof...(Fields);
144 static constexpr const char *names[] = { Fields::name ... };
145 static constexpr const size_t sizes[] = { Fields::size ... };
146 static constexpr const size_t sizes_fcoord[]
147 = { Fields::size_fcoord ... };
148 static constexpr const size_t dims[] = { Fields::dim ... };
149 static constexpr const size_t strides[] = { Fields::stride ... };
150 static constexpr const size_t strides_fcoord[]
151 = { Fields::stride_fcoord ... };
152
153 // we need to do arithmetic with the coordinate values, so we need to know their type
154 using sim_coord_t = typename extract_coord_type<Fields...>::value_type;
155
156 // store this information so we can use it to check order
157 static constexpr const FieldTypes field_type = field_type_;
158
159 // helper for the user so they don't have to remember in which order
160 // they passed the fields
161 template<typename T>
162 static constexpr size_t idx = find_idx<T, Fields...>();
163
164 static_assert( Nfields,
165 "empty field collection not allowed, need at least the "
166 "coordinate field" );
167
168 // check that all fields belong here, i.e. are Particle or Group fields
169 static_assert( all_valid({Fields::type...}),
170 "There is a Particle field in a Group type or vice versa." );
171
172 // check that the first field is indeed a coordinate field
173 static_assert( first_field_is_coord<Fields...>(),
174 "The first field in one type is not a coordinate field.");
175
176 // check that there is no duplication (which is not a problem per se but likely indicates a bug)
177 static_assert( all_unequal<Fields...>(),
178 "Duplicate field, this is likely not what you intended to do.");
179
180 // converts coords to global coordinate type if necessary
181 // this function takes care of the necessary buffer reallocs
182 static void
183 convert_coords (size_t Nitems, void * &coords, coord_t rescale=1)
184 {
185 if constexpr (!std::is_same_v<sim_coord_t, coord_t>)
186 {
187 if constexpr (sizeof(coord_t) <= sizeof(sim_coord_t))
188 // we can work in the original buffer
189 {
190 // get some accessor-type pointers
191 coord_t *coords_global_type = (coord_t *)coords;
192 sim_coord_t *coords_sim_type = (sim_coord_t *)coords;
193
194 // do the conversion
195 for (size_t ii=0; ii != Nitems * dims[0]; ++ii)
196 coords_global_type[ii] = (coord_t)(coords_sim_type[ii]);
197
198 // resize to save memory
199 coords = std::realloc(coords, Nitems * dims[0] * sizeof(coord_t));
200 }
201 else
202 // we need to enlarge the new buffer
203 {
204 // make more space, preserving the data
205 coords = std::realloc(coords, Nitems * dims[0] * sizeof(coord_t));
206
207 // get some accessor-type pointers
208 coord_t *coords_global_type = (coord_t *)coords;
209 sim_coord_t *coords_sim_type
210 = (sim_coord_t *)((char *)coords + Nitems * dims[0]
211 * (sizeof(coord_t)-sizeof(sim_coord_t)));
212
213 // move the data to the back of the buffer
214 std::memmove(coords_sim_type, coords, Nitems * dims[0] * sizeof(sim_coord_t));
215
216 // do the conversion
217 for (size_t ii=0; ii != Nitems * dims[0]; ++ii)
218 coords_global_type[ii] = (coord_t)(coords_sim_type[ii]);
219 }
220 }
221
222 // do the rescaling if necessary
223 if (std::fabs(std::log(rescale)) > 1e-8) {
224 auto *x = (coord_t *)coords;
225 for (size_t ii=0; ii != Nitems * dims[0]; ++ii)
226 x[ii] *= rescale;
227 }
228 }
229};//}}}
230
235template<typename... Fields>
237
242template<typename... Fields>
244
250template<typename GroupFields_, typename ParticleFields_>
252{
253 using GroupFields = GroupFields_;
254 using ParticleFields = ParticleFields_;
255
256 static_assert( GroupFields::field_type == FieldTypes::GrpFld,
257 "First template parameter for AllFields must be a GrpFields type" );
258 static_assert( ParticleFields::field_type == FieldTypes::PrtFld,
259 "Second template parameter for AllFields must be a PrtFields type" );
260
261 static void print_field_info ()
262 {
263 print_field_info_fct<GroupFields>("GroupFields");
264 print_field_info_fct<ParticleFields>("ParticleFields");
265 }
266
267 AllFields () = delete;
268
269private :
270 template<typename Fields>
271 static void print_field_info_fct (const char *FieldsName)
272 {
273 std::fprintf(stderr, "In the FieldsCollection %s are contained :\n", FieldsName);
274 for (size_t ii=0; ii != Fields::Nfields; ++ii)
275 std::fprintf(stderr, "\t[%2lu] %-20s stride : %2lu byte\n",
276 ii, Fields::names[ii], Fields::strides[ii]);
277 }
278
279};
280
281#endif // FIELDS_HPP
Template to define a "bundle" of fields.
Definition fields.hpp:85
float coord_t
Internal coordinate type.
Definition fields.hpp:28
FieldTypes
Fields fall into two categories, group and particle fields.
Definition fields.hpp:33
Convenience type that bundles the group and particle fields.
Definition fields.hpp:252