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 */
25template<unsigned int dim, typename G_v, int prp>
26struct 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 */
39template<unsigned int dim, typename G_v>
40struct 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
76template<unsigned int dim, int lin_id, typename dT, typename G_v, typename v, int impl>
77class 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
94public:
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
139template<unsigned int dim, int lin_id, typename dT, typename G_v, typename v>
140class fill_prop<dim, lin_id, dT, G_v, v, 0>
141{
142
143public:
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
183template<unsigned int dim, int lin_id, typename dT, typename G_v, typename v>
184class 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
201public:
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 */
233template<unsigned int dim, int i, typename p, typename Graph, int ... pos>
234struct 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 */
257template<unsigned int dim, typename p, typename Graph, int ... pos>
258struct 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
275template<unsigned int dim, int lin_id, typename Graph, int se, typename T, unsigned int dim_c, int ... pos>
276class Graph_constructor_impl
277{
278public:
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
396template<unsigned int dim, int lin_id, typename Graph, typename T, unsigned int dim_c, int ... pos>
397class Graph_constructor_impl<dim, lin_id, Graph, NO_EDGE, T, dim_c, pos...>
398{
399public:
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
506template<unsigned int dim, typename Graph>
507class CartesianGraphFactory
508{
509
510public:
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