1 | /* |
2 | * CartesianGraphFactory.hpp |
3 | * |
4 | * Created on: Nov 28, 2014 |
5 | * Author: i-bird |
6 | */ |
7 | |
8 | #ifndef CARTESIANGRAPHFACTORY_HPP_ |
9 | #define CARTESIANGRAPHFACTORY_HPP_ |
10 | |
11 | #include "Vector/map_vector.hpp" |
12 | #include "Graph/map_graph.hpp" |
13 | #include "Grid/grid_sm.hpp" |
14 | #include "Space/Shape/Box.hpp" |
15 | #include "Space/Shape/HyperCube.hpp" |
16 | |
17 | #define NO_VERTEX_ID -1 |
18 | |
19 | /*! \brief Operator to fill the property 'prp' with the linearization of indexes |
20 | * |
21 | * \tparam dim Dimension of the space |
22 | * \tparam G_v Graph |
23 | * \tparam prp Property to fill |
24 | */ |
25 | template<unsigned int dim, typename G_v, int prp> |
26 | struct fill_id |
27 | { |
28 | //! function that fill with linearization indexes |
29 | static inline void fill(G_v & g_v, const grid_key_dx<dim> & gk, const grid_sm<dim, void> & gs) |
30 | { |
31 | g_v.template get<prp>() = gs.LinId(gk); |
32 | } |
33 | }; |
34 | /*! \brief Operator to fill the property in case there are no properties |
35 | * |
36 | * \tparam dim Dimension of the space |
37 | * \tparam G_v Graph |
38 | */ |
39 | template<unsigned int dim, typename G_v> |
40 | struct fill_id<dim, G_v, NO_VERTEX_ID> |
41 | { |
42 | //! function that fill with linearization indexes |
43 | static inline void fill(G_v & g_v, const grid_key_dx<dim> & gk, const grid_sm<dim, void> & gs) |
44 | { |
45 | } |
46 | }; |
47 | |
48 | /*! \brief This class work as a functor |
49 | * |
50 | * For each number in the boost::mpl::vector (for example 3 6) set the properties of the vertex at the |
51 | * specified id (3 6) with pos[d] * spacing[d] with d running from 0 to 1, pos[d] the position id of the vertex |
52 | * spacing the grid spacing |
53 | * |
54 | * Example |
55 | * |
56 | * if we give a grid_key of dimension 2 4x4 the expression "pos[d] * spacing[d]" |
57 | * will assume the value |
58 | * |
59 | * (0.0 0.0) (0.25 0.0) ...... (1.0 0.0) |
60 | * (0.0 0.25)................. (1.0 0.25) |
61 | * .................................... |
62 | * (0.0 1.0).................. (1.0 1.0) |
63 | * |
64 | * and the properties 3 6 will be filled with the numbers 0.0 0.0 ....... 1.0 1.0 |
65 | * progressively |
66 | * |
67 | * \tparam dim Dimensionality of the cartesian grid |
68 | * \tparam dT type of the domain |
69 | * \tparam G_v vertex type object |
70 | * \tparam v boost::mpl::vector containing all the index to fill |
71 | * \tparam is_stub when is true, produce a trivial operator(), |
72 | * to use when v is an empty vector to avoid compilation error |
73 | * |
74 | */ |
75 | |
76 | template<unsigned int dim, int lin_id, typename dT, typename G_v, typename v, int impl> |
77 | class fill_prop |
78 | { |
79 | //! Domain |
80 | const Box<dim,dT> & domain; |
81 | |
82 | //! Reference to an array containing the spacing |
83 | const dT (&szd)[dim]; |
84 | |
85 | //! grid_key_dx Reference containing the actual position |
86 | grid_key_dx<dim> & gk; |
87 | |
88 | //! Vertex object to fill |
89 | G_v & g_v; |
90 | |
91 | //! grid info |
92 | const grid_sm<dim, void> & gs; |
93 | |
94 | public: |
95 | |
96 | //! Fill the object from where to take the properties |
97 | fill_prop(G_v & g_v, const dT (&szd)[dim], grid_key_dx<dim> & gk, const grid_sm<dim, void> & gs, const Box<dim,dT> & domain) |
98 | :domain(domain), szd(szd), gk(gk), g_v(g_v), gs(gs) |
99 | { |
100 | } |
101 | |
102 | //! It call the function for each property we want to copy |
103 | template<typename T> |
104 | void operator()(T& t) const |
105 | { |
106 | typedef typename boost::fusion::result_of::at<v, boost::mpl::int_<T::value>>::type t_val; |
107 | |
108 | g_v.template get<t_val::value>() = gk.get(T::value) * szd[T::value] + domain.getLow(T::value); |
109 | fill_id<dim, G_v, lin_id>::fill(g_v, gk, gs); |
110 | } |
111 | }; |
112 | |
113 | /*! \brief This class work as a functor |
114 | * |
115 | * For each number in the boost::mpl::vector (for example 3 6) set the properties of the vertex at the |
116 | * specified id (3 6) with pos[d] * spacing[d] with d running from 0 to 1, pos[d] the position id of the vertex |
117 | * spacing the grid spacing |
118 | * |
119 | * Example |
120 | * |
121 | * if we give a grid_key of dimension 2 4x4 the expression "pos[d] * spacing[d]" |
122 | * will assume the value |
123 | * |
124 | * (0.0 0.0) (0.25 0.0) ...... (1.0 0.0) |
125 | * (0.0 0.25)................. (1.0 0.25) |
126 | * .................................... |
127 | * (0.0 1.0).................. (1.0 1.0) |
128 | * |
129 | * and the properties 3 6 will be filled with the numbers 0.0 0.0 ....... 1.0 1.0 |
130 | * progressively |
131 | * |
132 | * \tparam dim Dimensionality of the cartesian grid |
133 | * \tparam dT type of the domain |
134 | * \tparam G_v vertex type object |
135 | * \tparam v boost::mpl::vector containing all the index to fill |
136 | * |
137 | */ |
138 | |
139 | template<unsigned int dim, int lin_id, typename dT, typename G_v, typename v> |
140 | class fill_prop<dim, lin_id, dT, G_v, v, 0> |
141 | { |
142 | |
143 | public: |
144 | |
145 | //! Fill the object from where to take the properties |
146 | fill_prop(G_v & g_v, const dT (&szd)[dim], grid_key_dx<dim> & gk, const grid_sm<dim, void> & gs, const Box<dim,dT> & domain) |
147 | { |
148 | } |
149 | |
150 | //! It call the function for each property we want to copy |
151 | template<typename T> |
152 | void operator()(T& t) const |
153 | { |
154 | } |
155 | }; |
156 | |
157 | /*! \brief This class work as a functor |
158 | * |
159 | * For each number in the boost::mpl::vector (for example 3 6) set the properties of the vertex at the |
160 | * specified id (3 6) with pos[d] * spacing[d] with d running from 0 to 1, pos[d] the position id of the vertex |
161 | * spacing the grid spacing |
162 | * |
163 | * Example |
164 | * |
165 | * if we give a grid_key of dimension 2 4x4 the expression "pos[d] * spacing[d]" |
166 | * will assume the value |
167 | * |
168 | * (0.0 0.0) (0.25 0.0) ...... (1.0 0.0) |
169 | * (0.0 0.25)................. (1.0 0.25) |
170 | * .................................... |
171 | * (0.0 1.0).................. (1.0 1.0) |
172 | * |
173 | * and the properties 3 6 will be filled with the numbers 0.0 0.0 ....... 1.0 1.0 |
174 | * progressively |
175 | * |
176 | * \tparam dim Dimensionality of the cartesian grid |
177 | * \tparam dT type of the domain |
178 | * \tparam G_v vertex type object |
179 | * \tparam v boost::mpl::vector containing all the index to fill |
180 | * |
181 | */ |
182 | |
183 | template<unsigned int dim, int lin_id, typename dT, typename G_v, typename v> |
184 | class fill_prop<dim, lin_id, dT, G_v, v, 2> |
185 | { |
186 | //! Domain |
187 | const Box<dim,dT> & domain; |
188 | |
189 | //! Reference to an array containing the spacing |
190 | const dT (&szd)[dim]; |
191 | |
192 | //! grid_key_dx Reference containing the actual position |
193 | grid_key_dx<dim> & gk; |
194 | |
195 | //! Vertex object to fill |
196 | G_v & g_v; |
197 | |
198 | //! grid info |
199 | const grid_sm<dim, void> & gs; |
200 | |
201 | public: |
202 | |
203 | //! Fill the object from where to take the properties |
204 | fill_prop(G_v & g_v, const dT (&szd)[dim], grid_key_dx<dim> & gk, const grid_sm<dim, void> & gs, const Box<dim,dT> & domain) |
205 | :domain(domain), szd(szd), gk(gk), g_v(g_v), gs(gs) |
206 | { |
207 | } |
208 | |
209 | //! It call the function for each property we want to copy |
210 | template<typename T> |
211 | void operator()(T& t) const |
212 | { |
213 | typedef typename boost::fusion::result_of::at<v, boost::mpl::int_<0>>::type t_val; |
214 | typedef typename boost::mpl::at<typename G_v::T_type::type,t_val>::type s_type; |
215 | |
216 | for (size_t i = 0 ; i < std::extent<s_type>::value ; i++) |
217 | g_v.template get<t_val::value>()[i] = 0.0; |
218 | |
219 | for (size_t i = 0 ; i < dim ; i++) |
220 | g_v.template get<t_val::value>()[i] = gk.get(i) * static_cast<float>(szd[i]) + domain.getLow(i); |
221 | |
222 | fill_id<dim, G_v, lin_id>::fill(g_v, gk, gs); |
223 | } |
224 | }; |
225 | |
226 | /*! \brief Operator for vector and scalar property |
227 | * |
228 | * \tparam i Size of the property |
229 | * \tparam p Type of the property boost mpl |
230 | * \tparam Graph Graph |
231 | * \tparam pos Array of properties |
232 | */ |
233 | template<unsigned int dim, int i, typename p, typename Graph, int ... pos> |
234 | struct fill_prop_by_type |
235 | { |
236 | |
237 | //! Get the element 0 |
238 | typedef typename boost::mpl::at<p, boost::mpl::int_<0>>::type v_element; |
239 | |
240 | //! Get the property v_element (v_element is a number) |
241 | typedef typename boost::mpl::at<typename Graph::V_type::type, v_element>::type pos_prop_type; |
242 | |
243 | enum |
244 | { |
245 | value = ((sizeof...(pos) != 0) * (std::is_array<pos_prop_type>::value + 1)) |
246 | }; |
247 | |
248 | }; |
249 | |
250 | /*! \brief Operator for vector and scalar property in the case there are no properties |
251 | * |
252 | * \tparam i Size of the property |
253 | * \tparam p Type of the property |
254 | * \tparam Graph Graph |
255 | * \tparam pos Array of properties |
256 | */ |
257 | template<unsigned int dim, typename p, typename Graph, int ... pos> |
258 | struct fill_prop_by_type<dim, 0, p, Graph, pos...> |
259 | { |
260 | enum |
261 | { |
262 | value = 0 |
263 | }; |
264 | |
265 | }; |
266 | |
267 | /*! \brief Graph constructor function specialization |
268 | * |
269 | * On C++ partial function specialization is not allowed, so we need a class to do it |
270 | * |
271 | * \see CartesianGraphFactory method construct |
272 | * |
273 | */ |
274 | |
275 | template<unsigned int dim, int lin_id, typename Graph, int se, typename T, unsigned int dim_c, int ... pos> |
276 | class Graph_constructor_impl |
277 | { |
278 | public: |
279 | |
280 | /*! \brief Construct a cartesian graph |
281 | * |
282 | * \param sz size of the partesian graph |
283 | * \param dom domain where this cartesian graph is defined (used to fill the coordinates) |
284 | * \param bc boundary conditions (torus or cube) |
285 | * |
286 | * \return the constructed graph |
287 | * |
288 | */ |
289 | static Graph construct(const size_t (& sz)[dim], Box<dim,T> & dom, const size_t(& bc)[dim]) |
290 | { |
291 | // Calculate the size of the hyper-cubes on each dimension |
292 | T szd[dim]; |
293 | |
294 | for (size_t i = 0; i < dim; i++) |
295 | { |
296 | szd[i] = (dom.getHigh(i) - dom.getLow(i)) / sz[i]; |
297 | } |
298 | |
299 | //! Construct an hyper-cube of dimension dim |
300 | |
301 | HyperCube<dim> hc; |
302 | |
303 | // Construct a grid info |
304 | |
305 | grid_sm<dim, void> g(sz); |
306 | |
307 | // Create a graph with the number of vertices equal to the number of |
308 | // grid point |
309 | |
310 | //! Graph to construct |
311 | |
312 | Graph gp(g.size()); |
313 | |
314 | /****************** |
315 | * |
316 | * Create the edges and fill spatial |
317 | * information properties |
318 | * |
319 | ******************/ |
320 | |
321 | //! Construct a key iterator |
322 | grid_key_dx_iterator<dim> k_it(g); |
323 | |
324 | //! Iterate through all the elements |
325 | |
326 | while (k_it.isNext()) |
327 | { |
328 | grid_key_dx<dim> key = k_it.get(); |
329 | |
330 | // Vertex object |
331 | |
332 | auto obj = gp.vertex(g.LinId(key)); |
333 | |
334 | typedef typename to_boost_vmpl<pos...>::type p; |
335 | |
336 | // vertex spatial properties functor |
337 | |
338 | fill_prop<dim, lin_id, T, decltype(gp.vertex(g.LinId(key))), typename to_boost_vmpl<pos...>::type, fill_prop_by_type<dim,sizeof...(pos), p, Graph, pos...>::value> flp(obj, szd, key, g, dom); |
339 | |
340 | // fill properties |
341 | |
342 | boost::mpl::for_each<boost::mpl::range_c<int, 0, sizeof...(pos)> >(flp); |
343 | |
344 | // Get the combinations of dimension d |
345 | |
346 | for (long int d = dim-1 ; d >= dim_c ; d--) |
347 | { |
348 | // create the edges for that dimension |
349 | |
350 | std::vector<comb<dim>> c = hc.getCombinations_R(d); |
351 | |
352 | // for each combination calculate a safe linearization and create an edge |
353 | |
354 | for (size_t j = 0; j < c.size(); j++) |
355 | { |
356 | // Calculate the element size |
357 | |
358 | T ele_sz = 0; |
359 | |
360 | // for each dimension multiply and reduce |
361 | |
362 | |
363 | for (size_t s = 0 ; s < dim ; s++) |
364 | ele_sz += szd[s] * abs(c[j][s]); |
365 | |
366 | // Calculate the end point vertex id |
367 | // Calculate the start point id |
368 | |
369 | size_t start_v = g.LinId(key); |
370 | |
371 | size_t end_v = g.template LinId<CheckExistence>(key,c[j].getComb(),bc); |
372 | |
373 | // Add an edge and set the the edge property to the size of the face (communication weight) |
374 | gp.template addEdge<CheckExistence>(start_v, end_v).template get<se>() = ele_sz; |
375 | } |
376 | } |
377 | |
378 | // Fill vertex properties |
379 | |
380 | ++k_it; |
381 | } |
382 | |
383 | return gp; |
384 | } |
385 | }; |
386 | |
387 | /*! \brief Graph constructor function specialization |
388 | * |
389 | * On C++ partial function specialization is not allowed, so we need a class to do it |
390 | * This specialization handle the case when we have NO_EDGE option active |
391 | * |
392 | * \see CartesianGraphFactory method construct |
393 | * |
394 | */ |
395 | |
396 | template<unsigned int dim, int lin_id, typename Graph, typename T, unsigned int dim_c, int ... pos> |
397 | class Graph_constructor_impl<dim, lin_id, Graph, NO_EDGE, T, dim_c, pos...> |
398 | { |
399 | public: |
400 | |
401 | /*! \brief Construct a cartesian graph |
402 | * |
403 | * \param sz size of the partesian graph |
404 | * \param dom domain where this cartesian graph is defined (used to fill the coordinates) |
405 | * \param bc boundary conditions (torus or cube) |
406 | * |
407 | * \return the constructed graph |
408 | * |
409 | */ |
410 | static Graph construct(const size_t ( & sz)[dim], Box<dim,T> & dom, const size_t(& bc)[dim]) |
411 | { |
412 | // Calculate the size of the hyper-cubes on each dimension |
413 | |
414 | T szd[dim]; |
415 | |
416 | for (size_t i = 0; i < dim; i++) |
417 | { |
418 | szd[i] = (dom.getHigh(i) - dom.getLow(i)) / sz[i]; |
419 | } |
420 | |
421 | //! Construct an hyper-cube of dimension dim |
422 | |
423 | HyperCube<dim> hc; |
424 | |
425 | // Construct a grid info |
426 | |
427 | grid_sm<dim, void> g(sz); |
428 | |
429 | // Create a graph with the number of vertices equal to the number of |
430 | // grid point |
431 | |
432 | //! Graph to construct |
433 | |
434 | Graph gp(g.size()); |
435 | |
436 | /****************** |
437 | * |
438 | * Create the edges and fill spatial |
439 | * information properties |
440 | * |
441 | ******************/ |
442 | |
443 | //! Construct a key iterator |
444 | grid_key_dx_iterator<dim> k_it(g); |
445 | |
446 | //! Iterate through all the elements |
447 | |
448 | while (k_it.isNext()) |
449 | { |
450 | grid_key_dx<dim> key = k_it.get(); |
451 | |
452 | // Vertex object |
453 | auto obj = gp.vertex(g.LinId(key)); |
454 | |
455 | typedef typename to_boost_vmpl<pos...>::type p; |
456 | |
457 | // vertex spatial properties functor |
458 | |
459 | fill_prop<dim, lin_id, T, decltype(gp.vertex(g.LinId(key))), typename to_boost_vmpl<pos...>::type, fill_prop_by_type<dim,sizeof...(pos), p, Graph, pos...>::value> flp(obj, szd, key, g, dom); |
460 | |
461 | // fill properties |
462 | |
463 | boost::mpl::for_each_ref<boost::mpl::range_c<int, 0, sizeof...(pos)> >(flp); |
464 | |
465 | // Get the combinations of dimension d |
466 | |
467 | for (long int d = dim-1 ; d >= dim_c ; d--) |
468 | { |
469 | // create the edges for that dimension |
470 | |
471 | std::vector<comb<dim>> c = hc.getCombinations_R(d); |
472 | |
473 | // for each combination calculate a safe linearization and create an edge |
474 | |
475 | for (size_t j = 0; j < c.size(); j++) |
476 | { |
477 | // Calculate the end point vertex id |
478 | // Calculate the start point id |
479 | |
480 | size_t start_v = g.LinId(key); |
481 | |
482 | size_t end_v = g.template LinId<CheckExistence>(key,c[j].getComb(),bc); |
483 | |
484 | // Add an edge and set the the edge property to the size of the face (communication weight) |
485 | gp.template addEdge<CheckExistence>(start_v, end_v); |
486 | } |
487 | } |
488 | |
489 | // Fill vertex properties |
490 | |
491 | ++k_it; |
492 | } |
493 | |
494 | return gp; |
495 | } |
496 | }; |
497 | |
498 | /*! \brief This class construct a cartesian graph |
499 | * |
500 | * This class construct a cartesian graph |
501 | * |
502 | * \param dim dimensionality of the cartesian grid |
503 | * |
504 | */ |
505 | |
506 | template<unsigned int dim, typename Graph> |
507 | class CartesianGraphFactory |
508 | { |
509 | |
510 | public: |
511 | |
512 | /*! |
513 | * |
514 | * \brief Construct a cartesian graph, with V and E edge properties |
515 | * |
516 | * Construct a cartesian graph, with V and E edge properties |
517 | * |
518 | * Each vertex is a subspace (Hyper-cube) of dimension dim, each vertex is |
519 | * connected with an edge if two vertex (Hyper-cube) share a element of dimension grater than |
520 | * dim_c. One property can be used to store the contact size or the d-dimensional |
521 | * surface in common between two connected hyper-cube. |
522 | * |
523 | * \tparam se Indicate which properties fill with the contact size. The |
524 | * contact size is the point, line , surface, d-dimensional object size |
525 | * in contact (in common) between two hyper-cube. NO_EDGE indicate |
526 | * no property will store this information |
527 | * \tparam id_prp property 'id' that stores the vertex id (with -1 it skip) |
528 | * \tparam T type of the domain like (int real complex ... ) |
529 | * \tparam dim_c Connectivity dimension |
530 | * \tparam pos... (optional)one or more integer indicating the spatial properties |
531 | * |
532 | * \param sz store the size of the cartesian grid on each dimension |
533 | * \param dom Box enclosing the physical domain |
534 | * \param bc boundary conditions {PERIODIC = torus and NON_PERIODIC = cube} |
535 | * |
536 | * \return the constructed graph |
537 | * |
538 | */ |
539 | template<int se, int id_prp, typename T, unsigned int dim_c, int ... pos> |
540 | static Graph construct(const size_t (&sz)[dim], Box<dim, T> & dom, const size_t (& bc)[dim]) |
541 | { |
542 | return Graph_constructor_impl<dim, id_prp, Graph, se, T, dim_c, pos...>::construct(sz, dom, bc); |
543 | } |
544 | }; |
545 | |
546 | #endif /* CARTESIANGRAPHFACTORY_HPP_ */ |
547 | |