diff --git a/src/common/aka_iterators.hh b/src/common/aka_iterators.hh index 33860debb..5329181f4 100644 --- a/src/common/aka_iterators.hh +++ b/src/common/aka_iterators.hh @@ -1,309 +1,320 @@ /** * @file aka_iterators.hh * * @author Nicolas Richart * * @date creation Wed Jul 19 2017 * * @brief iterator interfaces * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_error.hh" /* -------------------------------------------------------------------------- */ #include #include #include +#include /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_AKA_ITERATORS_HH__ #define __AKANTU_AKA_ITERATORS_HH__ namespace akantu { namespace tuple { /* ------------------------------------------------------------------------ */ namespace details { template struct Foreach { template static inline decltype(auto) transform_forward(F && func, Tuple && tuple) { return std::tuple_cat( Foreach::transform_forward(std::forward(func), std::forward(tuple)), std::forward_as_tuple(std::forward(func)( std::get(std::forward(tuple))))); } template static inline decltype(auto) transform(F && func, Tuple && tuple) { return std::tuple_cat( Foreach::transform(std::forward(func), std::forward(tuple)), std::make_tuple(std::forward(func)( std::get(std::forward(tuple))))); } template static inline void foreach (F && func, Tuple && tuple) { Foreach::foreach (std::forward(func), std::forward(tuple)); std::forward(func)(std::get(std::forward(tuple))); } template static inline bool equal(Tuple && a, Tuple && b) { if (not(std::get(std::forward(a)) == std::get(std::forward(b)))) return false; return Foreach::equal(std::forward(a), std::forward(b)); } }; /* ------------------------------------------------------------------------ */ template <> struct Foreach<1> { template static inline decltype(auto) transform_forward(F && func, Tuple && tuple) { return std::forward_as_tuple( std::forward(func)(std::get<0>(std::forward(tuple)))); } template static inline decltype(auto) transform(F && func, Tuple && tuple) { return std::make_tuple( std::forward(func)(std::get<0>(std::forward(tuple)))); } template static inline void foreach (F && func, Tuple && tuple) { std::forward(func)(std::get<0>(std::forward(tuple))); } template static inline bool equal(Tuple && a, Tuple && b) { return std::get<0>(std::forward(a)) == std::get<0>(std::forward(b)); } }; } // namespace details /* ------------------------------------------------------------------------ */ template bool are_equal(Tuple && a, Tuple && b) { return details::Foreach>::value>::equal( std::forward(a), std::forward(b)); } template void foreach (F && func, Tuple && tuple) { details::Foreach>::value>::foreach ( std::forward(func), std::forward(tuple)); } template decltype(auto) transform_forward(F && func, Tuple && tuple) { return details::Foreach>::value>:: transform_forward(std::forward(func), std::forward(tuple)); } template decltype(auto) transform(F && func, Tuple && tuple) { return details::Foreach>::value>:: transform(std::forward(func), std::forward(tuple)); } } // namespace tuple namespace iterators { namespace details { struct dereference_iterator { template - typename Iter::reference operator()(Iter & it) const { - return *it; + decltype(auto) operator()(Iter & it) const { + return std::forward(*it); } }; struct increment_iterator { template void operator()(Iter & it) const { ++it; } }; struct begin_container { template decltype(auto) operator()(Container && cont) const { return std::forward(cont).begin(); } }; struct end_container { template decltype(auto) operator()(Container && cont) const { return std::forward(cont).end(); } }; } // namespace details /* ------------------------------------------------------------------------ */ template class ZipIterator { private: using tuple_t = std::tuple; - public: explicit ZipIterator(tuple_t iterators) : iterators(std::move(iterators)) {} decltype(auto) operator*() { return tuple::transform_forward(details::dereference_iterator(), iterators); } ZipIterator & operator++() { tuple::foreach (details::increment_iterator(), iterators); return *this; } bool operator==(const ZipIterator & other) const { return tuple::are_equal(iterators, other.iterators); } bool operator!=(const ZipIterator & other) const { return not operator==(other); } private: tuple_t iterators; }; } // namespace iterators /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ template decltype(auto) zip_iterator(std::tuple && iterators_tuple) { - auto zip = iterators::ZipIterator(std::move(iterators_tuple)); + auto zip = iterators::ZipIterator(std::forward(iterators_tuple)); return zip; } /* -------------------------------------------------------------------------- */ namespace containers { template class ZipContainer { - using containers_t = std::tuple; + using containers_t = std::tuple; public: explicit ZipContainer(Containers &&... containers) - : containers(std::forward_as_tuple(containers...)) {} + : containers(std::forward(containers)...) {} decltype(auto) begin() const { return zip_iterator( tuple::transform(iterators::details::begin_container(), std::forward(containers))); } decltype(auto) end() const { return zip_iterator( tuple::transform(iterators::details::end_container(), std::forward(containers))); } decltype(auto) begin() { return zip_iterator( tuple::transform(iterators::details::begin_container(), std::forward(containers))); } decltype(auto) end() { return zip_iterator( tuple::transform(iterators::details::end_container(), std::forward(containers))); } private: containers_t containers; }; } // namespace containers /* -------------------------------------------------------------------------- */ template decltype(auto) zip(Containers &&... conts) { - return containers::ZipContainer(conts...); + return containers::ZipContainer(std::forward(conts)...); } /* -------------------------------------------------------------------------- */ /* Arange */ /* -------------------------------------------------------------------------- */ namespace iterators { template class ArangeIterator { public: + using value_type = T; + using pointer = T*; + using reference = T&; + using iterator_category = std::input_iterator_tag; + constexpr ArangeIterator(T value, T step) : value(value), step(step) {} constexpr ArangeIterator(const ArangeIterator &) = default; constexpr ArangeIterator & operator++() { value += step; return *this; } - constexpr T operator*() { return value; } + constexpr const T & operator*() const { return value; } - constexpr bool operator==(const ArangeIterator & other) { - return value == other.value and step == other.step; + constexpr bool operator==(const ArangeIterator & other) const { + return (value == other.value) and (step == other.step); } - constexpr bool operator!=(const ArangeIterator & other) { + constexpr bool operator!=(const ArangeIterator & other) const { return not operator==(other); } private: - T value; - const T step; + T value{0}; + const T step{1}; }; } // namespace iterators namespace containers { template class ArangeContainer { public: using iterator = iterators::ArangeIterator; constexpr ArangeContainer(T start, T stop, T step = 1) : start(start), stop((stop - start)% step == 0 ? stop : start + (1 + (stop -start)/step)*step), step(step) {} explicit constexpr ArangeContainer(T stop) : ArangeContainer(0, stop, 1) {} constexpr T operator[](size_t i) { T val = start + i * step; assert(val < stop && "i is out of range"); return val; } constexpr size_t size() { return (stop - start) / step; } constexpr iterator begin() { return iterator(start, step); } constexpr iterator end() { return iterator(stop, step); } private: const T start{0}, stop{0}, step{1}; }; } // namespace containers template inline decltype(auto) arange(T stop) { return containers::ArangeContainer(stop); } template -inline decltype(auto) arange(T start, T stop, T step = 1) { +inline constexpr decltype(auto) arange(T start, T stop, T step = 1) { return containers::ArangeContainer(start, stop, step); } +template +inline constexpr decltype(auto) counting(Container && container) { + return zip(arange(std::forward(container).size()), + std::forward(container)); +} + } // namespace akantu #endif /* __AKANTU_AKA_ITERATORS_HH__ */ diff --git a/src/common/aka_static_if.hh b/src/common/aka_static_if.hh new file mode 100644 index 000000000..274a05295 --- /dev/null +++ b/src/common/aka_static_if.hh @@ -0,0 +1,105 @@ +// Copyright (c) 2016 Vittorio Romeo +// License: AFL 3.0 | https://opensource.org/licenses/AFL-3.0 +// http://vittorioromeo.info | vittorio.romeo@outlook.com + +#ifndef __AKANTU_AKA_STATIC_IF_HH__ +#define __AKANTU_AKA_STATIC_IF_HH__ + +#include + +#define FWD(...) ::std::forward(__VA_ARGS__) + +namespace akantu { +template using bool_ = std::integral_constant; + +template constexpr bool_ bool_v{}; + +template using int_ = std::integral_constant; + +template constexpr int_ int_v{}; + +template using sz_ = std::integral_constant; + +template constexpr sz_ sz_v{}; + +template auto static_if(TPredicate) noexcept; + +namespace impl { + template struct static_if_impl; + + template struct static_if_result; + + template auto make_static_if_result(TF && f) noexcept; + + template <> struct static_if_impl { + template auto & else_(TF &&) noexcept { + // Ignore `else_`, as the predicate is true. + return *this; + } + + template auto & else_if(TPredicate) noexcept { + // Ignore `else_if`, as the predicate is true. + return *this; + } + + template auto then(TF && f) noexcept { + // We found a matching branch, just make a result and + // ignore everything else. + return make_static_if_result(FWD(f)); + } + }; + + template <> struct static_if_impl { + template auto & then(TF &&) noexcept { + // Ignore `then`, as the predicate is false. + return *this; + } + + template auto else_(TF && f) noexcept { + // (Assuming that `else_` is after all `else_if` calls.) + + // We found a matching branch, just make a result and + // ignore everything else. + + return make_static_if_result(FWD(f)); + } + + template auto else_if(TPredicate) noexcept { + return static_if(TPredicate{}); + } + + template auto operator()(Ts &&...) noexcept { + // If there are no `else` branches, we must ignore calls + // to a failed `static_if` matching. + } + }; + + template + struct static_if_result : TFunctionToCall { + // Perfect-forward the function in the result instance. + template + explicit static_if_result(TFFwd && f) noexcept : TFunctionToCall(FWD(f)) {} + + // Ignore everything, we found a result. + template auto & then(TF &&) noexcept { return *this; } + + template auto & else_if(TPredicate) noexcept { + return *this; + } + + template auto & else_(TF &&) noexcept { return *this; } + }; + + template auto make_static_if_result(TF && f) noexcept { + return static_if_result{FWD(f)}; + } +} // namespace impl + +template auto static_if(TPredicate) noexcept { + return impl::static_if_impl{}; +} + +#undef FWD +} // namespace akantu + +#endif /* __AKANTU_AKA_STATIC_IF_HH__ */ diff --git a/src/mesh/mesh_iterators.hh b/src/mesh/mesh_iterators.hh index 1121458ba..7969b01dc 100644 --- a/src/mesh/mesh_iterators.hh +++ b/src/mesh/mesh_iterators.hh @@ -1,224 +1,237 @@ /** * @file mesh_iterators.hh * * @author Nicolas Richart * * @date creation Wed Aug 09 2017 * * @brief Set of helper classes to have fun with range based for * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "mesh.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_ITERATORS_HH__ #define __AKANTU_MESH_ITERATORS_HH__ namespace akantu { class MeshElementsByTypes { using elements_iterator = Array::scalar_iterator; public: explicit MeshElementsByTypes(const Array & elements) { this->elements.copy(elements); std::sort(this->elements.begin(), this->elements.end()); } /* ------------------------------------------------------------------------ */ class MeshElementsRange { public: MeshElementsRange() = default; MeshElementsRange(const elements_iterator & begin, const elements_iterator & end) : type((*begin).type), ghost_type((*begin).ghost_type), begin(begin), end(end) {} AKANTU_GET_MACRO(Type, type, const ElementType &); AKANTU_GET_MACRO(GhostType, ghost_type, const GhostType &); const Array & getElements() { elements.resize(end - begin); auto el_it = elements.begin(); for (auto it = begin; it != end; ++it, ++el_it) { *el_it = it->element; } return elements; } private: ElementType type{_not_defined}; GhostType ghost_type{_casper}; elements_iterator begin; elements_iterator end; Array elements; }; /* ------------------------------------------------------------------------ */ class iterator { struct element_comparator { bool operator()(const Element & lhs, const Element & rhs) const { bool res = ((lhs.kind < rhs.kind) || ((lhs.kind == rhs.kind) && ((lhs.ghost_type < rhs.ghost_type) || ((lhs.ghost_type == rhs.ghost_type) && ((lhs.type < rhs.type)))))); return res; } }; public: iterator(const iterator &) = default; iterator(const elements_iterator & first, const elements_iterator & last) : range(std::equal_range(first, last, *first, element_comparator())), first(first), last(last) {} decltype(auto) operator*() const { return MeshElementsRange(range.first, range.second); } iterator operator++() { first = range.second; range = std::equal_range(first, last, *first, element_comparator()); return *this; } bool operator==(const iterator & other) const { return (first == other.first and last == other.last); } bool operator!=(const iterator & other) const { return (not operator==(other)); } private: std::pair range; elements_iterator first; elements_iterator last; }; iterator begin() { return iterator(elements.begin(), elements.end()); } iterator end() { return iterator(elements.end(), elements.end()); } private: Array elements; }; /* -------------------------------------------------------------------------- */ namespace mesh_iterators { namespace details { template class delegated_iterator { public: + using value_type = std::remove_pointer_t; + using pointer = value_type*; + using reference = value_type&; + using iterator_category = std::input_iterator_tag; + explicit delegated_iterator(internal_iterator it) : it(std::move(it)) {} decltype(auto) operator*() { return std::forwardsecond))>(*(it->second)); } delegated_iterator operator++() { ++it; return *this; } - bool operator==(const delegated_iterator & other) { + bool operator==(const delegated_iterator & other) const { return other.it == it; } - bool operator!=(const delegated_iterator & other) { + bool operator!=(const delegated_iterator & other) const { return other.it != it; } private: internal_iterator it; }; - template class MeshElementGroups { + template class ElementGroupsIterable { public: - explicit MeshElementGroups(M && mesh) : mesh(std::forward(mesh)) {} + explicit ElementGroupsIterable(GroupManager && group_manager) + : group_manager(std::forward(group_manager)) {} + size_t size() { return group_manager.getNbElementGroups(); } decltype(auto) begin() { - return delegated_iterator( - mesh.element_group_begin()); + return delegated_iterator( + group_manager.element_group_begin()); } decltype(auto) begin() const { - return delegated_iterator( - mesh.element_group_begin()); + return delegated_iterator( + group_manager.element_group_begin()); } decltype(auto) end() { - return delegated_iterator( - mesh.element_group_end()); + return delegated_iterator( + group_manager.element_group_end()); } decltype(auto) end() const { - return delegated_iterator( - mesh.element_group_end()); + return delegated_iterator( + group_manager.element_group_end()); } private: - M && mesh; + GroupManager && group_manager; }; - template class MeshNodeGroups { + template class NodeGroupsIterable { public: - explicit MeshNodeGroups(M && mesh) : mesh(std::forward(mesh)) {} + explicit NodeGroupsIterable(GroupManager && group_manager) + : group_manager(std::forward(group_manager)) {} + size_t size() { return group_manager.getNbNodeGroups(); } decltype(auto) begin() { - return delegated_iterator( - mesh.node_group_begin()); + return delegated_iterator( + group_manager.node_group_begin()); } decltype(auto) begin() const { - return delegated_iterator( - mesh.node_group_begin()); + return delegated_iterator( + group_manager.node_group_begin()); } decltype(auto) end() { - return delegated_iterator( - mesh.node_group_end()); + return delegated_iterator( + group_manager.node_group_end()); } decltype(auto) end() const { - return delegated_iterator( - mesh.node_group_end()); + return delegated_iterator( + group_manager.node_group_end()); } private: - M && mesh; + GroupManager && group_manager; }; } // namespace details } // namespace mesh_iterators -template decltype(auto) MeshElementGroups(Mesh && mesh) { - return mesh_iterators::details::MeshElementGroups(mesh); +template +decltype(auto) ElementGroupsIterable(GroupManager && group_manager) { + return mesh_iterators::details::ElementGroupsIterable(group_manager); } -template decltype(auto) MeshNodeGroups(Mesh && mesh) { - return mesh_iterators::details::MeshNodeGroups(mesh); +template +decltype(auto) NodeGroupsIterable(GroupManager && group_manager) { + return mesh_iterators::details::NodeGroupsIterable(group_manager); } } // namespace akantu #endif /* __AKANTU_MESH_ITERATORS_HH__ */ diff --git a/src/mesh_utils/mesh_partition.cc b/src/mesh_utils/mesh_partition.cc index 01ee4574f..fbb583db9 100644 --- a/src/mesh_utils/mesh_partition.cc +++ b/src/mesh_utils/mesh_partition.cc @@ -1,410 +1,417 @@ /** * @file mesh_partition.cc * * @author David Simon Kammer * @author Nicolas Richart * * @date creation: Tue Aug 17 2010 * @date last modification: Fri Jan 22 2016 * * @brief implementation of common part of all partitioner * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "mesh_partition.hh" +#include "aka_iterators.hh" #include "aka_types.hh" #include "mesh_utils.hh" /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ MeshPartition::MeshPartition(const Mesh & mesh, UInt spatial_dimension, const ID & id, const MemoryID & memory_id) : Memory(id, memory_id), mesh(mesh), spatial_dimension(spatial_dimension), partitions("partition", id, memory_id), ghost_partitions("ghost_partition", id, memory_id), ghost_partitions_offset("ghost_partition_offset", id, memory_id), saved_connectivity("saved_connectivity", id, memory_id) { AKANTU_DEBUG_IN(); + Element elem; + elem.ghost_type = _not_ghost; + + for (auto && type : + mesh.elementTypes(spatial_dimension, _not_ghost, _ek_not_defined)) { + elem.type = type; + for (auto && i : arange(mesh.getNbElement(elem.type))) { + elem.element = i; + lin_to_element.push_back(elem); + } + } + AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ MeshPartition::~MeshPartition() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * TODO this function should most probably be rewritten in a more modern way * conversion in c++ of the GENDUALMETIS (mesh.c) function wrote by George in * Metis (University of Minnesota) */ void MeshPartition::buildDualGraph(Array & dxadj, Array & dadjncy, Array & edge_loads, const EdgeLoadFunctor & edge_load_func) { AKANTU_DEBUG_IN(); // tweak mesh; UInt nb_good_types = 0; std::vector nb_nodes_per_element_p1; std::vector magic_number; std::vector nb_element; std::vector *> conn; Element elem; elem.ghost_type = _not_ghost; UInt spatial_dimension = mesh.getSpatialDimension(); for (auto & type : mesh.elementTypes(spatial_dimension, _not_ghost, _ek_not_defined)) { elem.type = type; ElementType type_p1 = Mesh::getP1ElementType(type); conn.push_back( &const_cast &>(mesh.getConnectivity(type, _not_ghost))); nb_nodes_per_element_p1.push_back(Mesh::getNbNodesPerElement(type_p1)); nb_element.push_back(conn.back()->getSize()); magic_number.push_back( Mesh::getNbNodesPerElement(Mesh::getFacetType(type_p1))); - for (UInt i = 0; i < nb_element.back(); ++i) { - elem.element = i; - lin_to_element.push_back(elem); - } - ++nb_good_types; } CSR node_to_elem; MeshUtils::buildNode2Elements(mesh, node_to_elem); UInt nb_total_element = 0; UInt nb_total_node_element = 0; for (UInt t = 0; t < nb_good_types; ++t) { nb_total_element += nb_element[t]; nb_total_node_element += nb_element[t] * nb_nodes_per_element_p1[t]; } dxadj.resize(nb_total_element + 1); /// initialize the dxadj array for (UInt t = 0, linerized_el = 0; t < nb_good_types; ++t) for (UInt el = 0; el < nb_element[t]; ++el, ++linerized_el) dxadj(linerized_el) = nb_nodes_per_element_p1[t]; /// convert the dxadj_val array in a csr one for (UInt i = 1; i < nb_total_element; ++i) dxadj(i) += dxadj(i - 1); for (UInt i = nb_total_element; i > 0; --i) dxadj(i) = dxadj(i - 1); dxadj(0) = 0; dadjncy.resize(2 * dxadj(nb_total_element)); edge_loads.resize(2 * dxadj(nb_total_element)); /// weight map to determine adjacency std::unordered_map weight_map; for (UInt t = 0, linerized_el = 0; t < nb_good_types; ++t) { for (UInt el = 0; el < nb_element[t]; ++el, ++linerized_el) { /// fill the weight map for (UInt n = 0; n < nb_nodes_per_element_p1[t]; ++n) { UInt node = (*conn[t])(el, n); CSR::iterator k; for (k = node_to_elem.rbegin(node); k != node_to_elem.rend(node); --k) { Element current_element = *k; UInt current_el = lin_to_element.find(current_element); if (current_el <= linerized_el) break; auto it_w = weight_map.find(current_el); if (it_w == weight_map.end()) { weight_map[current_el] = 1; } else { it_w->second++; } } } /// each element with a weight of the size of a facet are adjacent for (auto it_w = weight_map.begin(); it_w != weight_map.end(); ++it_w) { if (it_w->second == magic_number[t]) { UInt adjacent_el = it_w->first; #if defined(AKANTU_COHESIVE_ELEMENT) /// Patch in order to prevent neighboring cohesive elements /// from detecting each other ElementKind linearized_el_kind = lin_to_element(linerized_el).kind; ElementKind adjacent_el_kind = lin_to_element(adjacent_el).kind; if (linearized_el_kind == adjacent_el_kind && linearized_el_kind == _ek_cohesive) continue; #endif UInt index_adj = dxadj(adjacent_el)++; UInt index_lin = dxadj(linerized_el)++; dadjncy(index_lin) = adjacent_el; dadjncy(index_adj) = linerized_el; } } weight_map.clear(); } } Int k_start = 0; for (UInt t = 0, linerized_el = 0, j = 0; t < nb_good_types; ++t) for (UInt el = 0; el < nb_element[t]; ++el, ++linerized_el) { for (Int k = k_start; k < dxadj(linerized_el); ++k, ++j) dadjncy(j) = dadjncy(k); dxadj(linerized_el) = j; k_start += nb_nodes_per_element_p1[t]; } for (UInt i = nb_total_element; i > 0; --i) dxadj(i) = dxadj(i - 1); dxadj(0) = 0; UInt adj = 0; for (UInt i = 0; i < nb_total_element; ++i) { UInt nb_adj = dxadj(i + 1) - dxadj(i); for (UInt j = 0; j < nb_adj; ++j, ++adj) { Int el_adj_id = dadjncy(dxadj(i) + j); Element el = lin_to_element(i); Element el_adj = lin_to_element(el_adj_id); Int load = edge_load_func(el, el_adj); edge_loads(adj) = load; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshPartition::fillPartitionInformation( const Mesh & mesh, const Int * linearized_partitions) { AKANTU_DEBUG_IN(); CSR node_to_elem; MeshUtils::buildNode2Elements(mesh, node_to_elem); UInt linearized_el = 0; - for (auto & type : mesh.elementTypes(spatial_dimension, _not_ghost, _ek_not_defined)) { + for (auto & type : + mesh.elementTypes(spatial_dimension, _not_ghost, _ek_not_defined)) { UInt nb_element = mesh.getNbElement(type); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); partitions.alloc(nb_element, 1, type, _not_ghost); auto & ghost_part_csr = ghost_partitions_csr(type, _not_ghost); ghost_part_csr.resizeRows(nb_element); ghost_partitions_offset.alloc(nb_element + 1, 1, type, _ghost); ghost_partitions.alloc(0, 1, type, _ghost); const Array & connectivity = mesh.getConnectivity(type, _not_ghost); for (UInt el = 0; el < nb_element; ++el, ++linearized_el) { UInt part = linearized_partitions[linearized_el]; partitions(type, _not_ghost)(el) = part; std::list list_adj_part; for (UInt n = 0; n < nb_nodes_per_element; ++n) { UInt node = connectivity.storage()[el * nb_nodes_per_element + n]; CSR::iterator ne; for (ne = node_to_elem.begin(node); ne != node_to_elem.end(node); ++ne) { const Element & adj_element = *ne; UInt adj_el = lin_to_element.find(adj_element); UInt adj_part = linearized_partitions[adj_el]; if (part != adj_part) { list_adj_part.push_back(adj_part); } } } list_adj_part.sort(); list_adj_part.unique(); for (auto & adj_part : list_adj_part) { ghost_part_csr.getRows().push_back(adj_part); ghost_part_csr.rowOffset(el)++; ghost_partitions(type, _ghost).push_back(adj_part); ghost_partitions_offset(type, _ghost)(el)++; } } ghost_part_csr.countToCSR(); /// convert the ghost_partitions_offset array in an offset array Array & ghost_partitions_offset_ptr = ghost_partitions_offset(type, _ghost); for (UInt i = 1; i < nb_element; ++i) ghost_partitions_offset_ptr(i) += ghost_partitions_offset_ptr(i - 1); for (UInt i = nb_element; i > 0; --i) ghost_partitions_offset_ptr(i) = ghost_partitions_offset_ptr(i - 1); ghost_partitions_offset_ptr(0) = 0; } // All Facets for (Int sp = spatial_dimension - 1; sp >= 0; --sp) { for (auto & type : mesh.elementTypes(sp, _not_ghost, _ek_not_defined)) { UInt nb_element = mesh.getNbElement(type); partitions.alloc(nb_element, 1, type, _not_ghost); AKANTU_DEBUG_INFO("Allocating partitions for " << type); auto & ghost_part_csr = ghost_partitions_csr(type, _not_ghost); ghost_part_csr.resizeRows(nb_element); ghost_partitions_offset.alloc(nb_element + 1, 1, type, _ghost); ghost_partitions.alloc(0, 1, type, _ghost); AKANTU_DEBUG_INFO("Allocating ghost_partitions for " << type); const Array> & elem_to_subelem = mesh.getElementToSubelement(type, _not_ghost); for (UInt i(0); i < mesh.getNbElement(type, _not_ghost); ++i) { // Facet loop const std::vector & adjacent_elems = elem_to_subelem(i); if (!adjacent_elems.empty()) { Element min_elem; UInt min_part(std::numeric_limits::max()); std::set adjacent_parts; for (UInt j(0); j < adjacent_elems.size(); ++j) { UInt adjacent_elem_id = adjacent_elems[j].element; UInt adjacent_elem_part = partitions(adjacent_elems[j].type, adjacent_elems[j].ghost_type)(adjacent_elem_id); if (adjacent_elem_part < min_part) { min_part = adjacent_elem_part; min_elem = adjacent_elems[j]; } adjacent_parts.insert(adjacent_elem_part); } partitions(type, _not_ghost)(i) = min_part; - auto git = - ghost_partitions_csr(min_elem.type, _not_ghost) - .begin(min_elem.element); - auto gend = - ghost_partitions_csr(min_elem.type, _not_ghost) - .end(min_elem.element); + auto git = ghost_partitions_csr(min_elem.type, _not_ghost) + .begin(min_elem.element); + auto gend = ghost_partitions_csr(min_elem.type, _not_ghost) + .end(min_elem.element); for (; git != gend; ++git) { adjacent_parts.insert(min_part); } adjacent_parts.erase(min_part); for (auto & part : adjacent_parts) { ghost_part_csr.getRows().push_back(part); ghost_part_csr.rowOffset(i)++; ghost_partitions(type, _ghost).push_back(part); } ghost_partitions_offset(type, _ghost)(i + 1) = ghost_partitions_offset(type, _ghost)(i + 1) + adjacent_elems.size(); } else { partitions(type, _not_ghost)(i) = 0; } } ghost_part_csr.countToCSR(); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshPartition::tweakConnectivity(const Array & pairs) { AKANTU_DEBUG_IN(); if (pairs.getSize() == 0) return; Mesh::type_iterator it = mesh.firstType(spatial_dimension, _not_ghost, _ek_not_defined); Mesh::type_iterator end = mesh.lastType(spatial_dimension, _not_ghost, _ek_not_defined); for (; it != end; ++it) { ElementType type = *it; Array & conn = const_cast &>(mesh.getConnectivity(type, _not_ghost)); UInt nb_nodes_per_element = conn.getNbComponent(); UInt nb_element = conn.getSize(); Array & saved_conn = saved_connectivity.alloc( nb_element, nb_nodes_per_element, type, _not_ghost); saved_conn.copy(conn); for (UInt i = 0; i < pairs.getSize(); ++i) { for (UInt el = 0; el < nb_element; ++el) { for (UInt n = 0; n < nb_nodes_per_element; ++n) { if (pairs(i, 1) == conn(el, n)) conn(el, n) = pairs(i, 0); } } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshPartition::restoreConnectivity() { AKANTU_DEBUG_IN(); ElementTypeMapArray::type_iterator it = saved_connectivity.firstType( spatial_dimension, _not_ghost, _ek_not_defined); ElementTypeMapArray::type_iterator end = saved_connectivity.lastType( spatial_dimension, _not_ghost, _ek_not_defined); for (; it != end; ++it) { ElementType type = *it; Array & conn = const_cast &>(mesh.getConnectivity(type, _not_ghost)); Array & saved_conn = saved_connectivity(type, _not_ghost); conn.copy(saved_conn); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/mesh_utils/mesh_partition/mesh_partition_scotch.cc b/src/mesh_utils/mesh_partition/mesh_partition_scotch.cc index 7ba52fd3c..f5994e699 100644 --- a/src/mesh_utils/mesh_partition/mesh_partition_scotch.cc +++ b/src/mesh_utils/mesh_partition/mesh_partition_scotch.cc @@ -1,478 +1,480 @@ /** * @file mesh_partition_scotch.cc * * @author David Simon Kammer * @author Nicolas Richart * * @date creation: Fri Jun 18 2010 * @date last modification: Fri Jan 22 2016 * * @brief implementation of the MeshPartitionScotch class * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ - +/* -------------------------------------------------------------------------- */ +#include "mesh_partition_scotch.hh" +#include "aka_common.hh" +#include "aka_random_generator.hh" +#include "aka_static_if.hh" +#include "mesh_utils.hh" /* -------------------------------------------------------------------------- */ #include #include - /* -------------------------------------------------------------------------- */ -#include "aka_common.hh" -#include "mesh_partition_scotch.hh" -#include "mesh_utils.hh" -/* -------------------------------------------------------------------------- */ #if !defined(AKANTU_USE_PTSCOTCH) #ifndef AKANTU_SCOTCH_NO_EXTERN extern "C" { #endif // AKANTU_SCOTCH_NO_EXTERN #include #ifndef AKANTU_SCOTCH_NO_EXTERN } #endif // AKANTU_SCOTCH_NO_EXTERN #else // AKANTU_USE_PTSCOTCH #include #endif // AKANTU_USE_PTSCOTCH namespace akantu { +namespace { + constexpr int scotch_version = int(SCOTCH_VERSION); +} + /* -------------------------------------------------------------------------- */ MeshPartitionScotch::MeshPartitionScotch(const Mesh & mesh, UInt spatial_dimension, const ID & id, const MemoryID & memory_id) : MeshPartition(mesh, spatial_dimension, id, memory_id) { AKANTU_DEBUG_IN(); -// check if the akantu types and Scotch one are consistent -#if __cplusplus > 199711L - static_assert(sizeof(Int) == sizeof(SCOTCH_Num), - "The integer type of Akantu does not match the one from Scotch"); -#else - AKANTU_DEBUG_ASSERT( + // check if the akantu types and Scotch one are consistent + static_assert( sizeof(Int) == sizeof(SCOTCH_Num), "The integer type of Akantu does not match the one from Scotch"); -#endif + + static_if(scotch_version >= 6) + .then([](auto && y) { SCOTCH_randomSeed(y); }) + .else_([](auto && y) { srandom(y); }) + (std::forward(RandomGenerator::seed())); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ static SCOTCH_Mesh * createMesh(const Mesh & mesh) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); UInt nb_nodes = mesh.getNbNodes(); UInt total_nb_element = 0; UInt nb_edge = 0; Mesh::type_iterator it = mesh.firstType(spatial_dimension); Mesh::type_iterator end = mesh.lastType(spatial_dimension); for (; it != end; ++it) { ElementType type = *it; UInt nb_element = mesh.getNbElement(type); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); total_nb_element += nb_element; nb_edge += nb_element * nb_nodes_per_element; } SCOTCH_Num vnodbas = 0; SCOTCH_Num vnodnbr = nb_nodes; SCOTCH_Num velmbas = vnodnbr; SCOTCH_Num velmnbr = total_nb_element; SCOTCH_Num * verttab = new SCOTCH_Num[vnodnbr + velmnbr + 1]; SCOTCH_Num * vendtab = verttab + 1; SCOTCH_Num * velotab = NULL; SCOTCH_Num * vnlotab = NULL; SCOTCH_Num * vlbltab = NULL; memset(verttab, 0, (vnodnbr + velmnbr + 1) * sizeof(SCOTCH_Num)); it = mesh.firstType(spatial_dimension); for (; it != end; ++it) { ElementType type = *it; if (Mesh::getSpatialDimension(type) != spatial_dimension) continue; UInt nb_element = mesh.getNbElement(type); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); const Array & connectivity = mesh.getConnectivity(type, _not_ghost); /// count number of occurrence of each node for (UInt el = 0; el < nb_element; ++el) { UInt * conn_val = connectivity.storage() + el * nb_nodes_per_element; for (UInt n = 0; n < nb_nodes_per_element; ++n) { verttab[*(conn_val++)]++; } } } /// convert the occurrence array in a csr one for (UInt i = 1; i < nb_nodes; ++i) verttab[i] += verttab[i - 1]; for (UInt i = nb_nodes; i > 0; --i) verttab[i] = verttab[i - 1]; verttab[0] = 0; /// rearrange element to get the node-element list SCOTCH_Num edgenbr = verttab[vnodnbr] + nb_edge; SCOTCH_Num * edgetab = new SCOTCH_Num[edgenbr]; UInt linearized_el = 0; it = mesh.firstType(spatial_dimension); for (; it != end; ++it) { ElementType type = *it; UInt nb_element = mesh.getNbElement(type); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); const Array & connectivity = mesh.getConnectivity(type, _not_ghost); for (UInt el = 0; el < nb_element; ++el, ++linearized_el) { UInt * conn_val = connectivity.storage() + el * nb_nodes_per_element; for (UInt n = 0; n < nb_nodes_per_element; ++n) edgetab[verttab[*(conn_val++)]++] = linearized_el + velmbas; } } for (UInt i = nb_nodes; i > 0; --i) verttab[i] = verttab[i - 1]; verttab[0] = 0; SCOTCH_Num * verttab_tmp = verttab + vnodnbr + 1; SCOTCH_Num * edgetab_tmp = edgetab + verttab[vnodnbr]; it = mesh.firstType(spatial_dimension); for (; it != end; ++it) { ElementType type = *it; UInt nb_element = mesh.getNbElement(type); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); const Array & connectivity = mesh.getConnectivity(type, _not_ghost); for (UInt el = 0; el < nb_element; ++el) { *verttab_tmp = *(verttab_tmp - 1) + nb_nodes_per_element; verttab_tmp++; UInt * conn = connectivity.storage() + el * nb_nodes_per_element; for (UInt i = 0; i < nb_nodes_per_element; ++i) { *(edgetab_tmp++) = *(conn++) + vnodbas; } } } SCOTCH_Mesh * meshptr = new SCOTCH_Mesh; SCOTCH_meshInit(meshptr); SCOTCH_meshBuild(meshptr, velmbas, vnodbas, velmnbr, vnodnbr, verttab, vendtab, velotab, vnlotab, vlbltab, edgenbr, edgetab); /// Check the mesh AKANTU_DEBUG_ASSERT(SCOTCH_meshCheck(meshptr) == 0, "Scotch mesh is not consistent"); #ifndef AKANTU_NDEBUG if (AKANTU_DEBUG_TEST(dblDump)) { /// save initial graph FILE * fmesh = fopen("ScotchMesh.msh", "w"); SCOTCH_meshSave(meshptr, fmesh); fclose(fmesh); /// write geometry file std::ofstream fgeominit; fgeominit.open("ScotchMesh.xyz"); - fgeominit << spatial_dimension << std::endl - << nb_nodes << std::endl; + fgeominit << spatial_dimension << std::endl << nb_nodes << std::endl; const Array & nodes = mesh.getNodes(); Real * nodes_val = nodes.storage(); for (UInt i = 0; i < nb_nodes; ++i) { fgeominit << i << " "; for (UInt s = 0; s < spatial_dimension; ++s) fgeominit << *(nodes_val++) << " "; fgeominit << std::endl; ; } fgeominit.close(); } #endif AKANTU_DEBUG_OUT(); return meshptr; } /* -------------------------------------------------------------------------- */ static void destroyMesh(SCOTCH_Mesh * meshptr) { AKANTU_DEBUG_IN(); SCOTCH_Num velmbas, vnodbas, vnodnbr, velmnbr, *verttab, *vendtab, *velotab, *vnlotab, *vlbltab, edgenbr, *edgetab, degrptr; SCOTCH_meshData(meshptr, &velmbas, &vnodbas, &velmnbr, &vnodnbr, &verttab, &vendtab, &velotab, &vnlotab, &vlbltab, &edgenbr, &edgetab, °rptr); delete[] verttab; delete[] edgetab; SCOTCH_meshExit(meshptr); delete meshptr; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshPartitionScotch::partitionate(UInt nb_part, const EdgeLoadFunctor & edge_load_func, const Array & pairs) { AKANTU_DEBUG_IN(); nb_partitions = nb_part; tweakConnectivity(pairs); AKANTU_DEBUG_INFO("Partitioning the mesh " << mesh.getID() << " in " << nb_part << " parts."); Array dxadj; Array dadjncy; Array edge_loads; buildDualGraph(dxadj, dadjncy, edge_loads, edge_load_func); /// variables that will hold our structures in scotch format SCOTCH_Graph scotch_graph; SCOTCH_Strat scotch_strat; /// description number and arrays for struct mesh for scotch SCOTCH_Num baseval = 0; // base numbering for element and // nodes (0 -> C , 1 -> fortran) SCOTCH_Num vertnbr = dxadj.getSize() - 1; // number of vertexes SCOTCH_Num * parttab; // array of partitions SCOTCH_Num edgenbr = dxadj(vertnbr); // twice the number of "edges" //(an "edge" bounds two nodes) SCOTCH_Num * verttab = dxadj.storage(); // array of start indices in edgetab SCOTCH_Num * vendtab = NULL; // array of after-last indices in edgetab SCOTCH_Num * velotab = NULL; // integer load associated with // every vertex ( optional ) SCOTCH_Num * edlotab = edge_loads.storage(); // integer load associated with // every edge ( optional ) SCOTCH_Num * edgetab = dadjncy.storage(); // adjacency array of every vertex SCOTCH_Num * vlbltab = NULL; // vertex label array (optional) /// Allocate space for Scotch arrays parttab = new SCOTCH_Num[vertnbr]; /// Initialize the strategy structure SCOTCH_stratInit(&scotch_strat); /// Initialize the graph structure SCOTCH_graphInit(&scotch_graph); /// Build the graph from the adjacency arrays SCOTCH_graphBuild(&scotch_graph, baseval, vertnbr, verttab, vendtab, velotab, vlbltab, edgenbr, edgetab, edlotab); #ifndef AKANTU_NDEBUG if (AKANTU_DEBUG_TEST(dblDump)) { /// save initial graph FILE * fgraphinit = fopen("GraphIniFile.grf", "w"); SCOTCH_graphSave(&scotch_graph, fgraphinit); fclose(fgraphinit); /// write geometry file std::ofstream fgeominit; fgeominit.open("GeomIniFile.xyz"); - fgeominit << spatial_dimension << std::endl - << vertnbr << std::endl; + fgeominit << spatial_dimension << std::endl << vertnbr << std::endl; const Array & nodes = mesh.getNodes(); Mesh::type_iterator f_it = mesh.firstType(spatial_dimension, _not_ghost, _ek_not_defined); Mesh::type_iterator f_end = mesh.lastType(spatial_dimension, _not_ghost, _ek_not_defined); Array::const_vector_iterator nodes_it = nodes.begin(spatial_dimension); UInt out_linerized_el = 0; for (; f_it != f_end; ++f_it) { ElementType type = *f_it; UInt nb_element = mesh.getNbElement(*f_it); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); const Array & connectivity = mesh.getConnectivity(type); Vector mid(spatial_dimension); for (UInt el = 0; el < nb_element; ++el) { mid.set(0.); for (UInt n = 0; n < nb_nodes_per_element; ++n) { UInt node = connectivity.storage()[nb_nodes_per_element * el + n]; mid += Vector(nodes_it[node]); } mid /= nb_nodes_per_element; fgeominit << out_linerized_el++ << " "; for (UInt s = 0; s < spatial_dimension; ++s) fgeominit << mid[s] << " "; fgeominit << std::endl; ; } } fgeominit.close(); } #endif /// Check the graph AKANTU_DEBUG_ASSERT(SCOTCH_graphCheck(&scotch_graph) == 0, "Graph to partition is not consistent"); /// Partition the mesh SCOTCH_graphPart(&scotch_graph, nb_part, &scotch_strat, parttab); /// Check the graph AKANTU_DEBUG_ASSERT(SCOTCH_graphCheck(&scotch_graph) == 0, "Partitioned graph is not consistent"); #ifndef AKANTU_NDEBUG if (AKANTU_DEBUG_TEST(dblDump)) { /// save the partitioned graph FILE * fgraph = fopen("GraphFile.grf", "w"); SCOTCH_graphSave(&scotch_graph, fgraph); fclose(fgraph); /// save the partition map std::ofstream fmap; fmap.open("MapFile.map"); fmap << vertnbr << std::endl; for (Int i = 0; i < vertnbr; i++) fmap << i << " " << parttab[i] << std::endl; fmap.close(); } #endif /// free the scotch data structures SCOTCH_stratExit(&scotch_strat); SCOTCH_graphFree(&scotch_graph); SCOTCH_graphExit(&scotch_graph); fillPartitionInformation(mesh, parttab); delete[] parttab; restoreConnectivity(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshPartitionScotch::reorder() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Reordering the mesh " << mesh.getID()); SCOTCH_Mesh * scotch_mesh = createMesh(mesh); UInt nb_nodes = mesh.getNbNodes(); SCOTCH_Strat scotch_strat; // SCOTCH_Ordering scotch_order; SCOTCH_Num * permtab = new SCOTCH_Num[nb_nodes]; SCOTCH_Num * peritab = NULL; SCOTCH_Num cblknbr = 0; SCOTCH_Num * rangtab = NULL; SCOTCH_Num * treetab = NULL; /// Initialize the strategy structure SCOTCH_stratInit(&scotch_strat); SCOTCH_Graph scotch_graph; SCOTCH_graphInit(&scotch_graph); SCOTCH_meshGraph(scotch_mesh, &scotch_graph); #ifndef AKANTU_NDEBUG if (AKANTU_DEBUG_TEST(dblDump)) { FILE * fgraphinit = fopen("ScotchMesh.grf", "w"); SCOTCH_graphSave(&scotch_graph, fgraphinit); fclose(fgraphinit); } #endif /// Check the graph // AKANTU_DEBUG_ASSERT(SCOTCH_graphCheck(&scotch_graph) == 0, // "Mesh to Graph is not consistent"); SCOTCH_graphOrder(&scotch_graph, &scotch_strat, permtab, peritab, &cblknbr, rangtab, treetab); SCOTCH_graphExit(&scotch_graph); SCOTCH_stratExit(&scotch_strat); destroyMesh(scotch_mesh); /// Renumbering UInt spatial_dimension = mesh.getSpatialDimension(); for (UInt g = _not_ghost; g <= _ghost; ++g) { GhostType gt = (GhostType)g; Mesh::type_iterator it = mesh.firstType(_all_dimensions, gt); Mesh::type_iterator end = mesh.lastType(_all_dimensions, gt); for (; it != end; ++it) { ElementType type = *it; UInt nb_element = mesh.getNbElement(type, gt); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); const Array & connectivity = mesh.getConnectivity(type, gt); UInt * conn = connectivity.storage(); for (UInt el = 0; el < nb_element * nb_nodes_per_element; ++el, ++conn) { *conn = permtab[*conn]; } } } /// \todo think of a in-place way to do it Real * new_coordinates = new Real[spatial_dimension * nb_nodes]; Real * old_coordinates = mesh.getNodes().storage(); for (UInt i = 0; i < nb_nodes; ++i) { memcpy(new_coordinates + permtab[i] * spatial_dimension, old_coordinates + i * spatial_dimension, spatial_dimension * sizeof(Real)); } memcpy(old_coordinates, new_coordinates, nb_nodes * spatial_dimension * sizeof(Real)); delete[] new_coordinates; delete[] permtab; AKANTU_DEBUG_OUT(); } -} // akantu +} // namespace akantu diff --git a/test/test_synchronizer/test_data_distribution.cc b/test/test_synchronizer/test_data_distribution.cc index 2efd1498e..cc042b24d 100644 --- a/test/test_synchronizer/test_data_distribution.cc +++ b/test/test_synchronizer/test_data_distribution.cc @@ -1,197 +1,173 @@ /** * @file test_data_distribution.cc * * @author Nicolas Richart * * @date creation: Fri Sep 05 2014 * @date last modification: Sun Oct 19 2014 * * @brief Test the mesh distribution on creation of a distributed synchonizer * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ -#include "aka_common.hh" +#include "aka_iterators.hh" +#include "aka_random_generator.hh" #include "element_group.hh" #include "element_synchronizer.hh" +#include "mesh_iterators.hh" #include "mesh_partition_mesh_data.hh" -#include "aka_random_generator.hh" - +/* -------------------------------------------------------------------------- */ +#include /* -------------------------------------------------------------------------- */ using namespace akantu; int main(int argc, char * argv[]) { initialize(argc, argv); const UInt spatial_dimension = 3; Mesh mesh_group_after(spatial_dimension, "after"); Mesh mesh_group_before(spatial_dimension, "before"); StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); if (prank == 0) { mesh_group_before.read("data_split.msh"); mesh_group_after.read("data_split.msh"); mesh_group_before.registerData("global_id"); mesh_group_after.registerData("global_id"); - for (Mesh::type_iterator tit = mesh_group_after.firstType(_all_dimensions); - tit != mesh_group_after.lastType(_all_dimensions); ++tit) { - Array & gidb = - mesh_group_before.getDataPointer("global_id", *tit); - Array & gida = - mesh_group_after.getDataPointer("global_id", *tit); - - Array::scalar_iterator ait = gida.begin(); - Array::scalar_iterator bit = gidb.begin(); - Array::scalar_iterator end = gida.end(); - for (UInt i = 0; ait != end; ++ait, ++i, ++bit) { - *bit = i; - *ait = i; + for (const auto & type : mesh_group_after.elementTypes(_all_dimensions)) { + auto & gidb = mesh_group_before.getDataPointer("global_id", type); + auto & gida = mesh_group_after.getDataPointer("global_id", type); + + for (auto && data : zip(arange(gida.getSize()), gida, gidb)) { + std::get<1>(data) = std::get<0>(data); + std::get<2>(data) = std::get<0>(data); } } } RandomGenerator::seed(1); mesh_group_before.distribute(); RandomGenerator::seed(1); mesh_group_after.distribute(); if (prank == 0) std::cout << mesh_group_after; - GroupManager::element_group_iterator grp_ait = - mesh_group_after.element_group_begin(); - GroupManager::element_group_iterator grp_end = - mesh_group_after.element_group_end(); - for (; grp_ait != grp_end; ++grp_ait) { - std::string grp = grp_ait->first; - const ElementGroup & bgrp = mesh_group_before.getElementGroup(grp); - const ElementGroup & agrp = *grp_ait->second; - - for (ghost_type_t::iterator git = ghost_type_t::begin(); - git != ghost_type_t::end(); ++git) { - GhostType ghost_type = *git; - - for (Mesh::type_iterator tit = - bgrp.firstType(_all_dimensions, ghost_type); - tit != bgrp.lastType(_all_dimensions, ghost_type); ++tit) { + for (const auto & agrp : ElementGroupsIterable(mesh_group_after)) { + const ElementGroup & bgrp = + mesh_group_before.getElementGroup(agrp.getName()); + + for (auto && ghost_type : ghost_types) { + for (const auto & type : bgrp.elementTypes(_all_dimensions, ghost_type)) { Array & gidb = mesh_group_before.getDataPointer( - "global_id", *tit, ghost_type); + "global_id", type, ghost_type); Array & gida = mesh_group_after.getDataPointer( - "global_id", *tit, ghost_type); + "global_id", type, ghost_type); - Array bgelem(bgrp.getElements(*tit, ghost_type)); - Array agelem(agrp.getElements(*tit, ghost_type)); + Array bgelem(bgrp.getElements(type, ghost_type)); + Array agelem(agrp.getElements(type, ghost_type)); - Array::scalar_iterator ait = agelem.begin(); - Array::scalar_iterator bit = bgelem.begin(); - Array::scalar_iterator end = agelem.end(); - for (; ait != end; ++ait, ++bit) { - *bit = gidb(*bit); - *ait = gida(*ait); - } + std::transform(agelem.begin(), agelem.end(), agelem.begin(), + [&gida](auto & i) { return gida(i); }); + std::transform(bgelem.begin(), bgelem.end(), bgelem.begin(), + [&gidb](auto & i) { return gidb(i); }); std::sort(bgelem.begin(), bgelem.end()); std::sort(agelem.begin(), agelem.end()); - if (!std::equal(bgelem.begin(), bgelem.end(), agelem.begin())) { - std::cerr << "The filters array for the group " << grp - << " and for the element type " << *tit << ", " + if (not std::equal(bgelem.begin(), bgelem.end(), agelem.begin())) { + std::cerr << "The filters array for the group " << agrp.getName() + << " and for the element type " << type << ", " << ghost_type << " do not match" << std::endl; debug::setDebugLevel(dblTest); std::cerr << bgelem << std::endl; std::cerr << agelem << std::endl; debug::debugger.exit(EXIT_FAILURE); } } } } - GroupManager::node_group_iterator ngrp_ait = - mesh_group_after.node_group_begin(); - GroupManager::node_group_iterator ngrp_end = - mesh_group_after.node_group_end(); - for (; ngrp_ait != ngrp_end; ++ngrp_ait) { - std::string grp = ngrp_ait->first; - const NodeGroup & bgrp = mesh_group_before.getNodeGroup(grp); - const NodeGroup & agrp = *ngrp_ait->second; + for (const auto & agrp : NodeGroupsIterable(mesh_group_after)) { + const NodeGroup & bgrp = mesh_group_before.getNodeGroup(agrp.getName()); const Array & gidb = mesh_group_before.getGlobalNodesIds(); const Array & gida = mesh_group_after.getGlobalNodesIds(); Array bgnode(0, 1); Array agnode(0, 1); - Array::const_scalar_iterator ait = agrp.begin(); - Array::const_scalar_iterator bit = bgrp.begin(); - Array::const_scalar_iterator end = agrp.end(); - for (; ait != end; ++ait, ++bit) { + for (auto && pair : zip(bgrp, agrp)) { + UInt a,b; + std::tie(b, a) = pair; if (psize > 1) { - if (mesh_group_before.isLocalOrMasterNode(*bit)) - bgnode.push_back(gidb(*bit)); + if (mesh_group_before.isLocalOrMasterNode(b)) + bgnode.push_back(gidb(b)); - if (mesh_group_after.isLocalOrMasterNode(*ait)) - agnode.push_back(gida(*ait)); + if (mesh_group_after.isLocalOrMasterNode(a)) + agnode.push_back(gida(a)); } } std::sort(bgnode.begin(), bgnode.end()); std::sort(agnode.begin(), agnode.end()); if (!std::equal(bgnode.begin(), bgnode.end(), agnode.begin())) { - std::cerr << "The filters array for the group " << grp << " do not match" + std::cerr << "The filters array for the group " << agrp.getName() << " do not match" << std::endl; debug::setDebugLevel(dblTest); std::cerr << bgnode << std::endl; std::cerr << agnode << std::endl; debug::debugger.exit(EXIT_FAILURE); } } mesh_group_after.getElementGroup("inside").setBaseName("after_inside"); mesh_group_after.getElementGroup("inside").dump(); mesh_group_after.getElementGroup("outside").setBaseName("after_outside"); mesh_group_after.getElementGroup("outside").dump(); mesh_group_after.getElementGroup("volume").setBaseName("after_volume"); mesh_group_after.getElementGroup("volume").dump(); mesh_group_before.getElementGroup("inside").setBaseName("before_inside"); mesh_group_before.getElementGroup("inside").dump(); mesh_group_before.getElementGroup("outside").setBaseName("before_outside"); mesh_group_before.getElementGroup("outside").dump(); mesh_group_before.getElementGroup("volume").setBaseName("before_volume"); mesh_group_before.getElementGroup("volume").dump(); finalize(); return EXIT_SUCCESS; }