/* * CartesianGraphFactory.hpp * * Created on: Nov 28, 2014 * Author: i-bird */ #ifndef CARTESIANGRAPHFACTORY_HPP_ #define CARTESIANGRAPHFACTORY_HPP_ #include "Vector/map_vector.hpp" #include "Graph/map_graph.hpp" #include "Grid/grid_sm.hpp" #include "Space/Shape/Box.hpp" #include "Space/Shape/HyperCube.hpp" #define NO_VERTEX_ID -1 /*! \brief Operator to fill the property 'prp' with the linearization of indexes * * \tparam dim Dimension of the space * \tparam G_v Graph * \tparam prp Property to fill */ template struct fill_id { static inline void fill(G_v & g_v, const grid_key_dx & gk, const grid_sm & gs) { g_v.template get() = gs.LinId(gk); } }; /*! \brief Operator to fill the property in case there are no properties * * \tparam dim Dimension of the space * \tparam G_v Graph */ template struct fill_id { static inline void fill(G_v & g_v, const grid_key_dx & gk, const grid_sm & gs) { } }; /*! \brief This class work as a functor * * For each number in the boost::mpl::vector (for example 3 6) set the properties of the vertex at the * specified id (3 6) with pos[d] * spacing[d] with d running from 0 to 1, pos[d] the position id of the vertex * spacing the grid spacing * * Example * * if we give a grid_key of dimension 2 4x4 the expression "pos[d] * spacing[d]" * will assume the value * * (0.0 0.0) (0.25 0.0) ...... (1.0 0.0) * (0.0 0.25)................. (1.0 0.25) * .................................... * (0.0 1.0).................. (1.0 1.0) * * and the properties 3 6 will be filled with the numbers 0.0 0.0 ....... 1.0 1.0 * progressively * * \tparam dim Dimensionality of the cartesian grid * \tparam dT type of the domain * \tparam G_v vertex type object * \tparam v boost::mpl::vector containing all the index to fill * \tparam is_stub when is true, produce a trivial operator(), * to use when v is an empty vector to avoid compilation error * */ template class fill_prop { //! Reference to an array containing the spacing const dT (&szd)[dim]; //! grid_key_dx Reference containing the actual position grid_key_dx & gk; //! Vertex object to fill G_v & g_v; //! grid info const grid_sm & gs; public: //! Fill the object from where to take the properties fill_prop(G_v & g_v, const dT (&szd)[dim], grid_key_dx & gk, const grid_sm & gs) : szd(szd), gk(gk), g_v(g_v), gs(gs) { } //! It call the function for each property we want to copy template void operator()(T& t) const { typedef typename boost::fusion::result_of::at>::type t_val; g_v.template get() = gk.get(T::value) * szd[T::value]; fill_id::fill(g_v, gk, gs); } }; /*! \brief This class work as a functor * * For each number in the boost::mpl::vector (for example 3 6) set the properties of the vertex at the * specified id (3 6) with pos[d] * spacing[d] with d running from 0 to 1, pos[d] the position id of the vertex * spacing the grid spacing * * Example * * if we give a grid_key of dimension 2 4x4 the expression "pos[d] * spacing[d]" * will assume the value * * (0.0 0.0) (0.25 0.0) ...... (1.0 0.0) * (0.0 0.25)................. (1.0 0.25) * .................................... * (0.0 1.0).................. (1.0 1.0) * * and the properties 3 6 will be filled with the numbers 0.0 0.0 ....... 1.0 1.0 * progressively * * \tparam dim Dimensionality of the cartesian grid * \tparam dT type of the domain * \tparam G_v vertex type object * \tparam v boost::mpl::vector containing all the index to fill * */ template class fill_prop { public: //! Fill the object from where to take the properties fill_prop(G_v & g_v, const dT (&szd)[dim], grid_key_dx & gk, const grid_sm & gs) { } //! It call the function for each property we want to copy template void operator()(T& t) const { } }; /*! \brief This class work as a functor * * For each number in the boost::mpl::vector (for example 3 6) set the properties of the vertex at the * specified id (3 6) with pos[d] * spacing[d] with d running from 0 to 1, pos[d] the position id of the vertex * spacing the grid spacing * * Example * * if we give a grid_key of dimension 2 4x4 the expression "pos[d] * spacing[d]" * will assume the value * * (0.0 0.0) (0.25 0.0) ...... (1.0 0.0) * (0.0 0.25)................. (1.0 0.25) * .................................... * (0.0 1.0).................. (1.0 1.0) * * and the properties 3 6 will be filled with the numbers 0.0 0.0 ....... 1.0 1.0 * progressively * * \tparam dim Dimensionality of the cartesian grid * \tparam dT type of the domain * \tparam G_v vertex type object * \tparam v boost::mpl::vector containing all the index to fill * */ template class fill_prop { //! Reference to an array containing the spacing const dT (&szd)[dim]; //! grid_key_dx Reference containing the actual position grid_key_dx & gk; //! Vertex object to fill G_v & g_v; //! grid info const grid_sm & gs; public: //! Fill the object from where to take the properties fill_prop(G_v & g_v, const dT (&szd)[dim], grid_key_dx & gk, const grid_sm & gs) : szd(szd), gk(gk), g_v(g_v), gs(gs) { } //! It call the function for each property we want to copy template void operator()(T& t) const { typedef typename boost::fusion::result_of::at>::type t_val; typedef typename boost::mpl::at::type s_type; for (size_t i = 0 ; i < std::extent::value ; i++) g_v.template get()[i] = 0.0; for (size_t i = 0 ; i < dim ; i++) g_v.template get()[i] = gk.get(i) * static_cast(szd[i]); fill_id::fill(g_v, gk, gs); } }; /*! \brief Operator for vector and scalar property * * \tparam i Size of the property * \tparam p Type of the property * \tparam Graph Graph * \tparam pos Array of properties */ template struct fill_prop_by_type { typedef typename boost::mpl::at>::type v_element; typedef typename boost::mpl::at::type pos_prop_type; enum { value = ((sizeof...(pos) != 0) * (std::is_array::value + 1)) }; }; /*! \brief Operator for vector and scalar property in the case there are no properties * * \tparam i Size of the property * \tparam p Type of the property * \tparam Graph Graph * \tparam pos Array of properties */ template struct fill_prop_by_type<0, p, Graph, pos...> { enum { value = 0 }; }; /*! \brief Graph constructor function specialization * * On C++ partial function specialization is not allowed, so we need a class to do it * * \see CartesianGraphFactory method construct * */ template class Graph_constructor_impl { public: //! Construct cartesian graph static Graph construct(const size_t (& sz)[dim], Box dom, const size_t(& bc)[dim]) { // Calculate the size of the hyper-cubes on each dimension T szd[dim]; for (size_t i = 0; i < dim; i++) { szd[i] = (dom.getHigh(i) - dom.getLow(i)) / sz[i]; } //! Construct an hyper-cube of dimension dim HyperCube hc; // Construct a grid info grid_sm g(sz); // Create a graph with the number of vertices equal to the number of // grid point //! Graph to construct Graph gp(g.size()); /****************** * * Create the edges and fill spatial * information properties * ******************/ //! Construct a key iterator grid_key_dx_iterator k_it(g); //! Iterate through all the elements while (k_it.isNext()) { grid_key_dx key = k_it.get(); // Vertex object auto obj = gp.vertex(g.LinId(key)); typedef typename to_boost_vmpl::type p; // vertex spatial properties functor fill_prop::type, fill_prop_by_type::value> flp(obj, szd, key, g); // fill properties boost::mpl::for_each >(flp); // Get the combinations of dimension d for (long int d = dim-1 ; d >= dim_c ; d--) { // create the edges for that dimension std::vector> c = hc.getCombinations_R(d); // for each combination calculate a safe linearization and create an edge for (size_t j = 0; j < c.size(); j++) { // Calculate the element size T ele_sz = 0; // for each dimension multiply and reduce for (size_t s = 0 ; s < dim ; s++) ele_sz += szd[s] * abs(c[j][s]); // Calculate the end point vertex id // Calculate the start point id size_t start_v = g.LinId(key); size_t end_v = g.template LinId(key,c[j].getComb(),bc); // Add an edge and set the the edge property to the size of the face (communication weight) gp.template addEdge(start_v, end_v).template get() = ele_sz; } } // Fill vertex properties ++k_it; } return gp; } }; /*! \brief Graph constructor function specialization * * On C++ partial function specialization is not allowed, so we need a class to do it * This specialization handle the case when we have NO_EDGE option active * * \see CartesianGraphFactory method construct * */ template class Graph_constructor_impl { public: //! Construct cartesian graph static Graph construct(const size_t ( & sz)[dim], Box dom, const size_t(& bc)[dim]) { // Calculate the size of the hyper-cubes on each dimension T szd[dim]; for (size_t i = 0; i < dim; i++) { szd[i] = (dom.getHigh(i) - dom.getLow(i)) / sz[i]; } //! Construct an hyper-cube of dimension dim HyperCube hc; // Construct a grid info grid_sm g(sz); // Create a graph with the number of vertices equal to the number of // grid point //! Graph to construct Graph gp(g.size()); /****************** * * Create the edges and fill spatial * information properties * ******************/ //! Construct a key iterator grid_key_dx_iterator k_it(g); //! Iterate through all the elements while (k_it.isNext()) { grid_key_dx key = k_it.get(); // Vertex object auto obj = gp.vertex(g.LinId(key)); typedef typename to_boost_vmpl::type p; // vertex spatial properties functor fill_prop::type, fill_prop_by_type::value> flp(obj, szd, key, g); // fill properties boost::mpl::for_each_ref >(flp); // Get the combinations of dimension d for (long int d = dim-1 ; d >= dim_c ; d--) { // create the edges for that dimension std::vector> c = hc.getCombinations_R(d); // for each combination calculate a safe linearization and create an edge for (size_t j = 0; j < c.size(); j++) { // Calculate the end point vertex id // Calculate the start point id size_t start_v = g.LinId(key); size_t end_v = g.template LinId(key,c[j].getComb(),bc); // Add an edge and set the the edge property to the size of the face (communication weight) gp.template addEdge(start_v, end_v); } } // Fill vertex properties ++k_it; } return gp; } }; /*! \brief This class construct a cartesian graph * * This class construct a cartesian graph * * \param dim dimensionality of the cartesian grid * */ template class CartesianGraphFactory { public: /*! * * \brief Construct a cartesian graph, with V and E edge properties * * Construct a cartesian graph, with V and E edge properties * * Each vertex is a subspace (Hyper-cube) of dimension dim, each vertex is * connected with an edge if two vertex (Hyper-cube) share a element of dimension grater than * dim_c. One property can be used to store the contact size or the d-dimensional * surface in common between two connected hyper-cube. * * \param sz Vector that store the size of the grid on each dimension * \param dom Box enclosing the physical domain * * \tparam se Indicate which properties fill with the contact size. The * contact size is the point, line , surface, d-dimensional object size * in contact (in common) between two hyper-cube. NO_EDGE indicate * no property will store this information * \tparam T type of the domain like (int real complex ... ) * \tparam dim_c Connectivity dimension * \tparam pos... (optional)one or more integer indicating the spatial properties * */ /* template static Graph construct(const size_t (& sz)[dim], Box dom ) { return Graph_constructor_impl::construct(sz,dom,bc); }*/ /*! * * \brief Construct a cartesian graph, with V and E edge properties * * Construct a cartesian graph, with V and E edge properties * * Each vertex is a subspace (Hyper-cube) of dimension dim, each vertex is * connected with an edge if two vertex (Hyper-cube) share a element of dimension grater than * dim_c. One property can be used to store the contact size or the d-dimensional * surface in common between two connected hyper-cube. * * \param sz Vector that store the size of the grid on each dimension * \param dom Box enclosing the physical domain * \param bc boundary conditions {PERIODIC and NON_PERIODIC} * * \tparam se Indicate which properties fill with the contact size. The * contact size is the point, line , surface, d-dimensional object size * in contact (in common) between two hyper-cube. NO_EDGE indicate * no property will store this information * \tparam id_prp property 'id' that stores the vertex id (with -1 it skip) * \tparam T type of the domain like (int real complex ... ) * \tparam dim_c Connectivity dimension * \tparam pos... (optional)one or more integer indicating the spatial properties * */ template static Graph construct(const size_t (&sz)[dim], Box dom, const size_t (& bc)[dim]) { return Graph_constructor_impl::construct(sz, dom, bc); } }; #endif /* CARTESIANGRAPHFACTORY_HPP_ */